update unittest
This commit is contained in:
@@ -106,6 +106,7 @@
|
||||
- ✅ 灵活自定义LLM接口
|
||||
- ✅ 支持mac os
|
||||
- [ ] 支持多语言本地化
|
||||
- [ ] 开始游戏时的游戏设定栏
|
||||
|
||||
### 🗺️ 世界系统
|
||||
- ✅ 基础tile地块系统
|
||||
|
||||
@@ -37,12 +37,11 @@ class NurtureWeapon(TimedAction):
|
||||
if random.random() < total_chance:
|
||||
treasure_weapon = get_random_weapon_by_realm(Realm.Foundation_Establishment, self.avatar.weapon.weapon_type)
|
||||
if treasure_weapon:
|
||||
import copy
|
||||
old_weapon_name = self.avatar.weapon.name
|
||||
old_proficiency = self.avatar.weapon_proficiency
|
||||
# 深拷贝宝物兵器并更换(会重新计算长期效果)
|
||||
# get_random_weapon_by_realm 已经返回了副本,但再次copy也无妨
|
||||
new_weapon = copy.deepcopy(treasure_weapon)
|
||||
new_weapon = treasure_weapon.instantiate()
|
||||
self.avatar.change_weapon(new_weapon)
|
||||
# 恢复熟练度(change_weapon 会归零,需要手动恢复)
|
||||
self.avatar.weapon_proficiency = old_proficiency
|
||||
|
||||
@@ -6,10 +6,11 @@ from typing import Optional, Dict
|
||||
from src.utils.df import game_configs, get_str, get_int
|
||||
from src.classes.effect import load_effect_from_str
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.item import Item
|
||||
|
||||
|
||||
@dataclass
|
||||
class Auxiliary:
|
||||
class Auxiliary(Item):
|
||||
"""
|
||||
辅助装备类:提供各种辅助功能的装备
|
||||
字段与 static/game_configs/auxiliary.csv 对应:
|
||||
@@ -107,8 +108,7 @@ auxiliaries_by_id, auxiliaries_by_name = _load_auxiliaries()
|
||||
def get_random_auxiliary_by_realm(realm: Realm) -> Optional[Auxiliary]:
|
||||
"""获取指定境界的随机辅助装备"""
|
||||
import random
|
||||
import copy
|
||||
candidates = [a for a in auxiliaries_by_id.values() if a.realm == realm]
|
||||
if not candidates:
|
||||
return None
|
||||
return copy.deepcopy(random.choice(candidates))
|
||||
return random.choice(candidates).instantiate()
|
||||
|
||||
@@ -207,7 +207,6 @@ class InventoryMixin:
|
||||
包括扣款、获得物品(服用/入包/装备)、以旧换新。
|
||||
返回交易报告 dict。
|
||||
"""
|
||||
import copy
|
||||
from src.classes.elixir import Elixir
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
@@ -240,7 +239,7 @@ class InventoryMixin:
|
||||
|
||||
elif isinstance(obj, (Weapon, Auxiliary)):
|
||||
# 装备需要深拷贝
|
||||
new_equip = copy.deepcopy(obj)
|
||||
new_equip = obj.instantiate()
|
||||
|
||||
# 尝试卖出旧装备并换上新装备
|
||||
sold_name, refund = self._equip_and_trade_in(new_equip)
|
||||
|
||||
@@ -26,13 +26,13 @@ class CirculationManager:
|
||||
return
|
||||
# 使用深拷贝存储,防止外部修改影响记录
|
||||
# 注意:这里假设 weapon 对象是可以被 copy 的
|
||||
self.sold_weapons.append(copy.deepcopy(weapon))
|
||||
self.sold_weapons.append(weapon.instantiate())
|
||||
|
||||
def add_auxiliary(self, auxiliary: "Auxiliary") -> None:
|
||||
"""记录一件流出的辅助装备"""
|
||||
if auxiliary is None:
|
||||
return
|
||||
self.sold_auxiliaries.append(copy.deepcopy(auxiliary))
|
||||
self.sold_auxiliaries.append(auxiliary.instantiate())
|
||||
|
||||
def to_save_dict(self) -> dict:
|
||||
"""序列化为字典以便存档"""
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import copy
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Union, Optional
|
||||
@@ -9,6 +8,7 @@ from typing import Dict, List, Union, Optional
|
||||
from src.utils.df import game_configs, get_str, get_int
|
||||
from src.classes.effect import load_effect_from_str, format_effects_to_text
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.item import Item
|
||||
|
||||
|
||||
class ElixirType(Enum):
|
||||
@@ -21,7 +21,7 @@ class ElixirType(Enum):
|
||||
|
||||
|
||||
@dataclass
|
||||
class Elixir:
|
||||
class Elixir(Item):
|
||||
"""
|
||||
丹药类
|
||||
字段与 static/game_configs/elixir.csv 对应
|
||||
@@ -196,4 +196,6 @@ def get_elixirs_by_realm(realm: Realm) -> List[Elixir]:
|
||||
def get_random_elixir_by_realm(realm: Realm) -> Optional[Elixir]:
|
||||
"""获取指定境界的随机丹药"""
|
||||
candidates = get_elixirs_by_realm(realm)
|
||||
return copy.deepcopy(random.choice(candidates))
|
||||
if not candidates:
|
||||
return None
|
||||
return random.choice(candidates).instantiate()
|
||||
|
||||
16
src/classes/item.py
Normal file
16
src/classes/item.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import copy
|
||||
from typing import TypeVar, Any
|
||||
|
||||
T = TypeVar("T", bound="Item")
|
||||
|
||||
class Item:
|
||||
"""所有物品的基类"""
|
||||
|
||||
def instantiate(self: T) -> T:
|
||||
"""
|
||||
创建该物品的一个新实例。
|
||||
默认行为是深拷贝,适用于有独立状态的物品(如装备)。
|
||||
子类如果是只读对象(如材料),可以重写此方法返回 self 以优化性能。
|
||||
"""
|
||||
return copy.deepcopy(self)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from src.classes.item import Item
|
||||
from src.utils.df import game_configs, get_str, get_int
|
||||
from src.classes.cultivation import Realm
|
||||
|
||||
@dataclass
|
||||
class Material:
|
||||
class Material(Item):
|
||||
"""
|
||||
材料
|
||||
"""
|
||||
@@ -13,6 +14,9 @@ class Material:
|
||||
desc: str
|
||||
realm: Realm
|
||||
|
||||
def instantiate(self) -> "Material":
|
||||
return self
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.id)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import random
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Optional, Dict
|
||||
@@ -9,10 +8,11 @@ from src.utils.df import game_configs, get_str, get_int
|
||||
from src.classes.effect import load_effect_from_str
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.weapon_type import WeaponType
|
||||
from src.classes.item import Item
|
||||
|
||||
|
||||
@dataclass
|
||||
class Weapon:
|
||||
class Weapon(Item):
|
||||
"""
|
||||
兵器类:用于战斗的装备
|
||||
字段与 static/game_configs/weapon.csv 对应:
|
||||
@@ -118,4 +118,4 @@ def get_random_weapon_by_realm(realm: Realm, weapon_type: Optional[WeaponType] =
|
||||
|
||||
if not candidates:
|
||||
return None
|
||||
return copy.deepcopy(random.choice(candidates))
|
||||
return random.choice(candidates).instantiate()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
id,name,desc,member_act_style,alignment,weight,preferred_weapon,effects,rank_names
|
||||
,,宗门名称与描述,宗门成员行事风格,阵营(正/中立/邪),权重(默认1),倾向兵器类型,"effects(JSON形式,支持宽松格式,见effects.py说明)",自定义职位(掌门;长老;内门;外门)
|
||||
1,明心剑宗,"通玄界东方第一宗,以无上剑道称雄于世。云纹禁制为不传心法。【剑道专精】作为剑修,你使用剑类兵器时战力惊人,且在剑道上的感悟速度远超常人。",清明克己,行止如一。重剑与心法并重,讲究明心见性。,正,1,剑,"{extra_battle_strength_points: 3, extra_weapon_proficiency_gain: 0.5}",
|
||||
1,明心剑宗,"通玄界东方第一宗,以无上剑道称雄于世。云纹阵法为不传心法。【剑道专精】作为剑修,你使用剑类兵器时战力惊人,且在剑道上的感悟速度远超常人。",清明克己,行止如一。重剑与心法并重,讲究明心见性。,正,1,剑,"{extra_battle_strength_points: 3, extra_weapon_proficiency_gain: 0.5}",
|
||||
2,百兽宗,"以驯养灵兽闻名,豢养各种妖兽灵怪为战力。【御兽大师】你拥有独特的御兽天赋,捕捉妖兽对你来说轻而易举,善于驱使兽群为你而战。",言语直接,重视力量与血性,崇尚狩猎与搏斗。,邪,1,鞭,"{extra_catch_success_rate: 0.25, extra_hunt_materials: 1}",谷主;供奉;驭兽师;扈从
|
||||
3,水镜宗,"正道十宗之一,实则严守中立。拥有仙界异宝""彻天水镜""可预知未来。【趋吉避凶】你拥有超乎常人的直觉,视野开阔,且极易在探索中发现奇遇。",处事冷静圆融,喜以柔克刚,擅借力与反制。,中立,1,扇,"{extra_observation_radius: 2, extra_fortune_probability: 0.002, extra_refine_success_rate: 0.05}",镜主;掌镜人;传人;侍镜
|
||||
4,冥王宗,"行走幽冥之道,术法阴冷狠厉。【通幽】你修行幽冥之法,心志坚定,突破瓶颈时心无杂念,成功率更高。",言辞冷厉少情,敬畏因果而不惧杀伐,偏向效率与结果。,邪,1,扇,"{extra_breakthrough_success_rate: 0.1}",殿主;判官;无常;鬼卒
|
||||
@@ -10,7 +10,7 @@ id,name,desc,member_act_style,alignment,weight,preferred_weapon,effects,rank_nam
|
||||
8,幽魂噬影宗,"镇宗典籍《幽冥录》。幽明气为根基。【如影随形】你极擅身法与遁术,遇到危险时总能全身而退,亦能伺机刺杀落单之敌。",行事隐秘果断,重结果轻虚名,擅潜行与出其不意。,邪,1,刀,"{extra_escape_success_rate: 0.4, extra_assassinate_success_rate: 0.15}",门主;护法;影卫;探子
|
||||
9,千帆城,"炼器大宗,巧匠云集。著名法宝有灵灭丝、定魂蓝星等。商旅云集,自成体系。【巧夺天工】你深谙炼器与经商之道,温养兵器时常能使其脱胎换骨,且在交易中总能获利。",务实精明,重交易与信誉,崇尚规则与秩序。,中立,1,枪,"{extra_item_sell_price_multiplier: 0.05, extra_weapon_upgrade_chance: 0.15, extra_cast_success_rate: 0.05, shop_buy_price_reduction: 0.05}",城主;大供奉;执事;学徒
|
||||
10,妙化宗,"精擅音律杀伐与精神操控,功法诡谲阴柔,以无形琴音乱人心智,杀人于无形。【魔音贯耳】你擅长以音律乱人心智,灵力深厚绵长,虽不擅肉搏,但手段诡谲。",文雅缥缈中深藏算计,喜用言语与音律掌控局势,杀伐不沾烟火气。,邪,1,琴,"{extra_escape_success_rate: 0.5, extra_misfortune_probability: -0.005}",
|
||||
11,回玄宗,"当世第一阵法大派,以禁制阵诀独步天下,讲究阵法推演与巧思妙用。【阵法聚灵】你善用阵法辅助修炼,能够聚集天地灵气,修炼速度快于常人,且常有意外收获。",严谨细致,追求技术极致,战斗中擅长以后手禁制反制敌人,步步为营。,正,1,暗器,"{cultivate_duration_reduction: 0.1, extra_fortune_probability: 0.005}",
|
||||
11,回玄宗,"当世第一阵法大派,以阵法阵诀独步天下,讲究阵法推演与巧思妙用。【阵法聚灵】你善用阵法辅助修炼,能够聚集天地灵气,修炼速度快于常人,且常有意外收获。",严谨细致,追求技术极致,战斗中擅长以后手阵法反制敌人,步步为营。,正,1,暗器,"{cultivate_duration_reduction: 0.1, extra_fortune_probability: 0.005}",
|
||||
12,不夜城,"修习极光玄真法,以万里极光壁的绝对防御闻名于世。【生生不息】你的生命力极其顽强,疗伤效果倍增,寿元亦远超同阶修士。",坚韧顽强,在逆境中图强,行事光明磊落但也深谋远虑,极其护短。,正,1,扇,"{extra_hp_recovery_rate: 0.5, extra_max_lifespan: 20}",城主;阁老;执令;守夜人
|
||||
13,天行健宗,"专修浩然之气,行事正大光明,刚健果决,对邪魔外道有极强的克制力。【浩然正气】你养浩然之气,气脉悠长,面对境界低于自己的敌人时,能发挥出极强的压制力。",恪守原则,讲究道义,除魔卫道一马当先,宁折不弯。,正,1,剑,"{realm_suppression_bonus: 0.15}",
|
||||
14,噬魔宗,"通玄界第一魔宗,行事霸道残忍,擅长搜精噬血与肉体魔功。【搜刮成性】你崇尚力量与掠夺,搜刮凡人虽有伤天和,但能为你带来惊人的财富与资源。",强者为尊,随心所欲,崇尚绝对的力量与杀戮,视众生为血食。,邪,1,刀,"{extra_plunder_multiplier: 2.0, extra_battle_strength_points: 2}",
|
||||
|
||||
|
@@ -9,8 +9,8 @@ ID以4开头(400+sect_id),宗门驻地名称,宗门驻地描述,对应宗门ID
|
||||
407,落魂海,位于极南海上。镇魂海常年有妖兽作乱,海域凶险。宗门建筑立于海中礁岛之上,以镇魂钟为中心,钟声可震慑方圆千里之内的妖魂。,7
|
||||
408,鬼门湖,鬼门湖位于原始森林深处,重重大山围拢的平原地带。参天巨木、缠绕藤蔓、终日浮游不散的瘴气,还有因宗门秘法而生就的层层迷雾,将这里与外界完全隔离,透不进一点光来。,8
|
||||
409,天星海,千帆城建于天星海中央的巨型浮岛之上,整座城池由无数法器拼接而成,城外海面上停泊着数以千计的法器灵舟,帆樯如林,蔚为壮观。城中高塔林立,每座塔顶都有炼器炉火日夜不息,烟柱冲天。,9
|
||||
410,心园,四季如春,百花不谢。园内亭台楼阁错落,丝竹之声终日不绝,看似人间仙境,实则暗藏无数音杀禁制。,10
|
||||
411,诸隐山,诸隐山云雾缭绕,山势晦暗不明。整座山脉被无数重叠的禁制大阵覆盖,一步一景,一步一险,若无通形令牌,外人踏入半步便会迷失其中。,11
|
||||
410,心园,四季如春,百花不谢。园内亭台楼阁错落,丝竹之声终日不绝,看似人间仙境,实则暗藏无数音杀阵法。,10
|
||||
411,诸隐山,诸隐山云雾缭绕,山势晦暗不明。整座山脉被无数重叠的阵法大阵覆盖,一步一景,一步一险,若无通形令牌,外人踏入半步便会迷失其中。,11
|
||||
412,大千光极城,常年笼罩在绚丽的极光之下。城池由万年寒冰与玄铁铸就,在漫天极光的映照下流光溢彩,宛如神迹,是极寒之地唯一的温暖所在。,12
|
||||
413,浩然峰,位于通玄界中腹,山势雄奇挺拔,直插云霄。峰顶常年白云浩渺,紫气东来,书声琅琅之声可传十里,是天下浩然正气汇聚之地。,13
|
||||
414,陷空山,位于极西之地的险恶山脉,山势如犬牙交错,穷山恶水。山中常有血雾弥漫,怪石嶙峋,随处可见被吸干精血的兽骨枯尸,令人闻风丧胆。,14
|
||||
|
||||
|
97
tests/README.md
Normal file
97
tests/README.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# 单元测试指南
|
||||
|
||||
本文档旨在指导如何为《修仙模拟器》编写和维护单元测试。
|
||||
|
||||
## 目录结构
|
||||
|
||||
* `tests/`: 所有的单元测试文件都应存放在此目录下。
|
||||
* `tests/conftest.py`: 包含全局共享的 Fixture 和 Helper 函数。
|
||||
* `tests/test_*.py`: 具体模块的测试文件。命名应与 `src` 下的模块对应,例如 `src/classes/action/buy.py` 对应 `tests/test_buy_action.py`。
|
||||
|
||||
## 运行测试
|
||||
|
||||
在项目根目录下运行:
|
||||
|
||||
```bash
|
||||
pytest
|
||||
```
|
||||
|
||||
或者运行特定文件:
|
||||
|
||||
```bash
|
||||
pytest tests/test_buy_action.py
|
||||
```
|
||||
|
||||
## 编写新测试
|
||||
|
||||
我们使用 `pytest` 框架。为了保持代码整洁(DRY),请遵循以下准则:
|
||||
|
||||
### 1. 使用共享 Fixture
|
||||
|
||||
不要在每个测试文件中重复创建测试用的 Avatar、Map 或 Item。请使用 `tests/conftest.py` 中提供的 Fixture:
|
||||
|
||||
* `base_world`: 提供一个基础的游戏世界环境。
|
||||
* `dummy_avatar`: 提供一个标准的测试用角色(位于(0,0),练气期,男性)。
|
||||
* `avatar_in_city`: 基于 `dummy_avatar`,但已将其置于城市中,并给予 1000 灵石,且背包为空。
|
||||
* `mock_item_data`: 提供一组标准的 Mock 物品(丹药、材料、兵器、法宝)以及它们对应的 mock 字典结构,方便用于 patch `resolution` 模块。
|
||||
* `mock_llm_managers`: 自动 Mock 掉所有 LLM 调用,防止测试跑大模型。
|
||||
|
||||
**示例:**
|
||||
|
||||
```python
|
||||
def test_my_feature(avatar_in_city, mock_item_data):
|
||||
# 直接使用准备好的角色
|
||||
assert avatar_in_city.magic_stone == 1000
|
||||
|
||||
# 获取标准测试物品
|
||||
test_sword = mock_item_data["obj_weapon"]
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
### 2. Mock 外部依赖
|
||||
|
||||
对于 Action 测试,通常需要 Mock `src.utils.resolution` 中的查找字典。请结合 `mock_item_data` 使用 `unittest.mock.patch`。
|
||||
|
||||
**示例:**
|
||||
|
||||
```python
|
||||
from unittest.mock import patch
|
||||
|
||||
def test_action_logic(avatar_in_city, mock_item_data):
|
||||
materials_mock = mock_item_data["materials"]
|
||||
|
||||
with patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
# 此时系统中只有 mock_item_data 里定义的材料是可见的
|
||||
action = MyAction(avatar_in_city, avatar_in_city.world)
|
||||
action.execute("铁矿石")
|
||||
```
|
||||
|
||||
### 3. Action 测试模板
|
||||
|
||||
对于 `src.classes.action` 下的新 Action,建议测试以下三个方面:
|
||||
|
||||
1. **`can_start` (前置条件检查)**:
|
||||
* 测试成功情况。
|
||||
* 测试各种失败情况(如不在正确地点、资源不足、目标不存在等),并断言返回的错误 `reason`。
|
||||
2. **`start` (事件生成)**:
|
||||
* 验证返回的 `Event` 对象包含正确的描述文本。
|
||||
3. **`_execute` (执行逻辑)**:
|
||||
* 验证对 Avatar 状态的修改(扣钱、加物品、扣血、加熟练度等)。
|
||||
* 验证对 World 状态的修改。
|
||||
|
||||
### 4. Helper 函数
|
||||
|
||||
如果需要创建特定的测试对象,优先查看 `conftest.py` 中的 helper 函数:
|
||||
* `create_test_material(...)`
|
||||
* `create_test_weapon(...)`
|
||||
* `create_test_elixir(...)`
|
||||
* `create_test_auxiliary(...)`
|
||||
|
||||
如果发现新的通用需求,请将其添加到 `conftest.py` 而不是在测试文件中复制粘贴。
|
||||
|
||||
## 常见问题
|
||||
|
||||
* **`ModuleNotFoundError`**: 确保你的 IDE 或终端将项目根目录添加到了 `PYTHONPATH`。`pytest` 通常会自动处理这个问题。
|
||||
* **LLM 被调用了**: 确保你的测试(如果涉及 sim 循环)使用了 `mock_llm_managers` fixture,或者手动 patch 了相关模块。
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
from unittest.mock import MagicMock, AsyncMock, patch
|
||||
|
||||
from src.classes.map import Map
|
||||
from src.classes.tile import TileType
|
||||
from src.classes.tile import TileType, Tile
|
||||
from src.classes.world import World
|
||||
from src.classes.calendar import Month, Year, create_month_stamp
|
||||
from src.classes.avatar import Avatar, Gender
|
||||
@@ -10,6 +10,16 @@ from src.classes.age import Age
|
||||
from src.classes.cultivation import Realm
|
||||
from src.utils.id_generator import get_avatar_id
|
||||
from src.classes.name import get_random_name
|
||||
from src.classes.root import Root
|
||||
from src.classes.alignment import Alignment
|
||||
|
||||
# Action related imports
|
||||
from src.classes.elixir import Elixir, ElixirType
|
||||
from src.classes.material import Material
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.weapon_type import WeaponType
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.region import CityRegion
|
||||
|
||||
@pytest.fixture
|
||||
def base_map():
|
||||
@@ -26,9 +36,6 @@ def base_world(base_map):
|
||||
"""创建一个基于 base_map 的世界,时间为 Year 1, Jan"""
|
||||
return World(map=base_map, month_stamp=create_month_stamp(Year(1), Month.JANUARY))
|
||||
|
||||
from src.classes.root import Root
|
||||
from src.classes.alignment import Alignment
|
||||
|
||||
@pytest.fixture
|
||||
def dummy_avatar(base_world):
|
||||
"""创建一个位于 (0,0) 的标准男性练气期角色"""
|
||||
@@ -62,31 +69,15 @@ def dummy_avatar(base_world):
|
||||
def mock_llm_managers():
|
||||
"""
|
||||
Mock 所有涉及 LLM 调用的管理器和函数,防止测试中意外调用 LLM。
|
||||
包括:
|
||||
- llm_ai (decision making)
|
||||
- process_avatar_long_term_objective (long term goal)
|
||||
- process_avatar_nickname (nickname generation)
|
||||
- RelationResolver.run_batch (relationship evolution)
|
||||
"""
|
||||
from unittest.mock import patch, MagicMock, AsyncMock
|
||||
|
||||
with patch("src.sim.simulator.llm_ai") as mock_ai, \
|
||||
patch("src.sim.simulator.process_avatar_long_term_objective", new_callable=AsyncMock) as mock_lto, \
|
||||
patch("src.classes.nickname.process_avatar_nickname", new_callable=AsyncMock) as mock_nick, \
|
||||
patch("src.classes.relation_resolver.RelationResolver.run_batch", new_callable=AsyncMock) as mock_rr:
|
||||
|
||||
# 1. Mock AI Decision
|
||||
# ai.decide is an async method
|
||||
mock_ai.decide = AsyncMock(return_value={})
|
||||
|
||||
# 2. Mock Long Term Objective
|
||||
# AsyncMock returns a coroutine when called
|
||||
mock_lto.return_value = None
|
||||
|
||||
# 3. Mock Nickname
|
||||
mock_nick.return_value = None
|
||||
|
||||
# 4. Mock Relation Resolver
|
||||
mock_rr.return_value = []
|
||||
|
||||
yield {
|
||||
@@ -95,3 +86,100 @@ def mock_llm_managers():
|
||||
"nick": mock_nick,
|
||||
"rr": mock_rr
|
||||
}
|
||||
|
||||
# --- Shared Helpers for Item Creation ---
|
||||
|
||||
def create_test_elixir(name, realm, price=100, elixir_id=1, effects=None):
|
||||
if effects is None:
|
||||
effects = {"max_hp": 10}
|
||||
return Elixir(
|
||||
id=elixir_id,
|
||||
name=name,
|
||||
realm=realm,
|
||||
type=ElixirType.Breakthrough,
|
||||
desc="测试丹药",
|
||||
price=price,
|
||||
effects=effects
|
||||
)
|
||||
|
||||
def create_test_material(name, realm, material_id=101):
|
||||
return Material(
|
||||
id=material_id,
|
||||
name=name,
|
||||
desc="测试物品",
|
||||
realm=realm
|
||||
)
|
||||
|
||||
def create_test_weapon(name, realm, weapon_id=201):
|
||||
return Weapon(
|
||||
id=weapon_id,
|
||||
name=name,
|
||||
weapon_type=WeaponType.SWORD,
|
||||
realm=realm,
|
||||
desc="测试兵器",
|
||||
effects={},
|
||||
effect_desc=""
|
||||
)
|
||||
|
||||
def create_test_auxiliary(name, realm, aux_id=301):
|
||||
return Auxiliary(
|
||||
id=aux_id,
|
||||
name=name,
|
||||
realm=realm,
|
||||
desc="测试法宝",
|
||||
effects={},
|
||||
effect_desc=""
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def avatar_in_city(dummy_avatar):
|
||||
"""
|
||||
修改 dummy_avatar,使其位于城市中,并给予初始资金
|
||||
"""
|
||||
city_region = CityRegion(id=1, name="TestCity", desc="测试城市")
|
||||
tile = Tile(0, 0, TileType.CITY)
|
||||
tile.region = city_region
|
||||
|
||||
dummy_avatar.tile = tile
|
||||
dummy_avatar.magic_stone = 1000
|
||||
dummy_avatar.cultivation_progress.realm = Realm.Qi_Refinement
|
||||
dummy_avatar.elixirs = []
|
||||
dummy_avatar.materials = {} # 确保背包为空
|
||||
dummy_avatar.weapon = None
|
||||
dummy_avatar.auxiliary = None
|
||||
|
||||
return dummy_avatar
|
||||
|
||||
@pytest.fixture
|
||||
def mock_item_data():
|
||||
"""
|
||||
提供标准的一组测试物品,包括材料、丹药、兵器、法宝。
|
||||
返回一个包含这些对象的字典,方便后续 mock 使用。
|
||||
"""
|
||||
test_elixir = create_test_elixir("聚气丹", Realm.Qi_Refinement, price=100)
|
||||
high_level_elixir = create_test_elixir("筑基丹", Realm.Foundation_Establishment, price=1000, elixir_id=2)
|
||||
test_material = create_test_material("铁矿石", Realm.Qi_Refinement)
|
||||
test_weapon = create_test_weapon("青云剑", Realm.Qi_Refinement)
|
||||
test_auxiliary = create_test_auxiliary("聚灵珠", Realm.Qi_Refinement)
|
||||
|
||||
return {
|
||||
"elixirs": {
|
||||
"聚气丹": [test_elixir],
|
||||
"筑基丹": [high_level_elixir]
|
||||
},
|
||||
"materials": {
|
||||
"铁矿石": test_material
|
||||
},
|
||||
"weapons": {
|
||||
"青云剑": test_weapon
|
||||
},
|
||||
"auxiliaries": {
|
||||
"聚灵珠": test_auxiliary
|
||||
},
|
||||
# Direct access
|
||||
"obj_elixir": test_elixir,
|
||||
"obj_high_elixir": high_level_elixir,
|
||||
"obj_material": test_material,
|
||||
"obj_weapon": test_weapon,
|
||||
"obj_auxiliary": test_auxiliary
|
||||
}
|
||||
|
||||
@@ -1 +1,111 @@
|
||||
import pytest
|
||||
from unittest.mock import patch, MagicMock
|
||||
from src.classes.action.attack import Attack
|
||||
from src.classes.event import Event
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.avatar import Avatar
|
||||
|
||||
# 定义一个简单的 Result Mock
|
||||
class MockResolutionResult:
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
|
||||
def test_attack_can_start_success(dummy_avatar):
|
||||
"""测试攻击条件检查通过"""
|
||||
target = MagicMock(spec=Avatar)
|
||||
target.name = "TargetAvatar"
|
||||
target.is_dead = False
|
||||
|
||||
with patch("src.classes.action.attack.resolve_query") as mock_resolve:
|
||||
mock_resolve.return_value = MockResolutionResult(target)
|
||||
|
||||
action = Attack(dummy_avatar, dummy_avatar.world)
|
||||
can_start, reason = action.can_start("TargetAvatar")
|
||||
|
||||
assert can_start is True
|
||||
assert reason == ""
|
||||
|
||||
def test_attack_can_start_fail_no_target(dummy_avatar):
|
||||
"""测试目标不存在"""
|
||||
with patch("src.classes.action.attack.resolve_query") as mock_resolve:
|
||||
mock_resolve.return_value = MockResolutionResult(None)
|
||||
|
||||
action = Attack(dummy_avatar, dummy_avatar.world)
|
||||
can_start, reason = action.can_start("Ghost")
|
||||
|
||||
assert can_start is False
|
||||
assert "目标不存在" in reason
|
||||
|
||||
def test_attack_can_start_fail_dead_target(dummy_avatar):
|
||||
"""测试目标已死亡"""
|
||||
target = MagicMock(spec=Avatar)
|
||||
target.is_dead = True
|
||||
|
||||
with patch("src.classes.action.attack.resolve_query") as mock_resolve:
|
||||
mock_resolve.return_value = MockResolutionResult(target)
|
||||
|
||||
action = Attack(dummy_avatar, dummy_avatar.world)
|
||||
can_start, reason = action.can_start("Zombie")
|
||||
|
||||
assert can_start is False
|
||||
assert "目标已死亡" in reason
|
||||
|
||||
def test_attack_start_event(dummy_avatar):
|
||||
"""测试开始攻击生成的事件"""
|
||||
target = MagicMock(spec=Avatar)
|
||||
target.name = "Enemy"
|
||||
target.id = "enemy-id"
|
||||
|
||||
# Mock combat strength calculation
|
||||
with patch("src.classes.action.attack.resolve_query") as mock_resolve, \
|
||||
patch("src.classes.action.attack.get_effective_strength_pair") as mock_strength:
|
||||
|
||||
mock_resolve.return_value = MockResolutionResult(target)
|
||||
mock_strength.return_value = (100, 80)
|
||||
|
||||
action = Attack(dummy_avatar, dummy_avatar.world)
|
||||
event = action.start("Enemy")
|
||||
|
||||
assert isinstance(event, Event)
|
||||
assert "TestDummy" in event.content
|
||||
assert "Enemy" in event.content
|
||||
assert "100" in event.content # 战斗力显示
|
||||
assert event.is_major is True
|
||||
|
||||
def test_attack_execute_logic(dummy_avatar):
|
||||
"""测试执行战斗逻辑"""
|
||||
target = MagicMock(spec=Avatar)
|
||||
target.name = "Enemy"
|
||||
|
||||
# Setup HP mocks
|
||||
dummy_avatar.hp = MagicMock()
|
||||
target.hp = MagicMock()
|
||||
|
||||
# Setup proficiency mocks (methods on MagicMock)
|
||||
dummy_avatar.increase_weapon_proficiency = MagicMock()
|
||||
target.increase_weapon_proficiency = MagicMock()
|
||||
|
||||
with patch("src.classes.action.attack.resolve_query") as mock_resolve, \
|
||||
patch("src.classes.action.attack.decide_battle") as mock_decide:
|
||||
|
||||
mock_resolve.return_value = MockResolutionResult(target)
|
||||
|
||||
# winner, loser, loser_damage, winner_damage
|
||||
# 假设 dummy_avatar 赢了
|
||||
mock_decide.return_value = (dummy_avatar, target, 50, 10)
|
||||
|
||||
action = Attack(dummy_avatar, dummy_avatar.world)
|
||||
action._execute("Enemy")
|
||||
|
||||
# 验证伤害应用
|
||||
# loser (target) takes 50 dmg
|
||||
target.hp.reduce.assert_called_with(50)
|
||||
# winner (dummy) takes 10 dmg
|
||||
dummy_avatar.hp.reduce.assert_called_with(10)
|
||||
|
||||
# 验证熟练度增加
|
||||
assert dummy_avatar.increase_weapon_proficiency.called
|
||||
assert target.increase_weapon_proficiency.called
|
||||
|
||||
# 验证结果保存
|
||||
assert action._last_result == (dummy_avatar, target, 50, 10)
|
||||
|
||||
@@ -1,79 +1,16 @@
|
||||
import pytest
|
||||
from unittest.mock import patch, MagicMock
|
||||
from unittest.mock import patch
|
||||
from src.classes.action.buy import Buy
|
||||
from src.classes.region import CityRegion, Region
|
||||
from src.classes.elixir import Elixir, ElixirType, ConsumedElixir
|
||||
from src.classes.material import Material
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.weapon_type import WeaponType
|
||||
from src.classes.region import CityRegion
|
||||
from src.classes.elixir import ElixirType, ConsumedElixir
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.tile import Tile, TileType
|
||||
from tests.conftest import create_test_weapon # Explicitly import if needed, or rely on conftest being auto-loaded (it is)
|
||||
|
||||
# 创建一些测试用的对象
|
||||
def create_test_elixir(name, realm, price=100, elixir_id=1, effects=None):
|
||||
if effects is None:
|
||||
effects = {"max_hp": 10}
|
||||
return Elixir(
|
||||
id=elixir_id,
|
||||
name=name,
|
||||
realm=realm,
|
||||
type=ElixirType.Breakthrough,
|
||||
desc="测试丹药",
|
||||
price=price,
|
||||
effects=effects
|
||||
)
|
||||
|
||||
def create_test_material(name, realm, material_id=101):
|
||||
return Material(
|
||||
id=material_id,
|
||||
name=name,
|
||||
desc="测试物品",
|
||||
realm=realm
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def avatar_in_city(dummy_avatar):
|
||||
"""
|
||||
修改 dummy_avatar,使其位于城市中,并给予初始资金
|
||||
"""
|
||||
# 模拟 Tile 和 Region
|
||||
# Region init: id, name, desc, cors (default=[])
|
||||
city_region = CityRegion(id=1, name="TestCity", desc="测试城市")
|
||||
tile = Tile(0, 0, TileType.CITY)
|
||||
tile.region = city_region
|
||||
|
||||
dummy_avatar.tile = tile
|
||||
dummy_avatar.magic_stone = 1000 # 初始资金
|
||||
dummy_avatar.cultivation_progress.realm = Realm.Qi_Refinement # 练气期
|
||||
dummy_avatar.elixirs = [] # 清空已服用丹药
|
||||
|
||||
return dummy_avatar
|
||||
|
||||
@pytest.fixture
|
||||
def mock_objects():
|
||||
"""
|
||||
Mock elixirs_by_name 和 materials_by_name
|
||||
"""
|
||||
test_elixir = create_test_elixir("聚气丹", Realm.Qi_Refinement, price=100)
|
||||
high_level_elixir = create_test_elixir("筑基丹", Realm.Foundation_Establishment, price=1000, elixir_id=2)
|
||||
test_material = create_test_material("铁矿石", Realm.Qi_Refinement)
|
||||
|
||||
# elixirs_by_name 是 Dict[str, List[Elixir]]
|
||||
elixirs_mock = {
|
||||
"聚气丹": [test_elixir],
|
||||
"筑基丹": [high_level_elixir]
|
||||
}
|
||||
|
||||
# materials_by_name 是 Dict[str, Material]
|
||||
materials_mock = {
|
||||
"铁矿石": test_material
|
||||
}
|
||||
|
||||
return elixirs_mock, materials_mock, test_elixir, high_level_elixir, test_material
|
||||
|
||||
def test_buy_item_success(avatar_in_city, mock_objects):
|
||||
def test_buy_item_success(avatar_in_city, mock_item_data):
|
||||
"""测试购买普通材料成功"""
|
||||
elixirs_mock, materials_mock, _, _, test_material = mock_objects
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
test_material = mock_item_data["obj_material"]
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
@@ -95,9 +32,11 @@ def test_buy_item_success(avatar_in_city, mock_objects):
|
||||
assert avatar_in_city.magic_stone == initial_money - expected_price
|
||||
assert avatar_in_city.get_material_quantity(test_material) == 1
|
||||
|
||||
def test_buy_elixir_success(avatar_in_city, mock_objects):
|
||||
def test_buy_elixir_success(avatar_in_city, mock_item_data):
|
||||
"""测试购买并服用丹药成功"""
|
||||
elixirs_mock, materials_mock, test_elixir, _, _ = mock_objects
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
test_elixir = mock_item_data["obj_elixir"]
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
@@ -111,7 +50,6 @@ def test_buy_elixir_success(avatar_in_city, mock_objects):
|
||||
expected_price = int(test_elixir.price * 1.5)
|
||||
|
||||
# 模拟服用丹药的行为
|
||||
|
||||
action._execute("聚气丹")
|
||||
|
||||
assert avatar_in_city.magic_stone == initial_money - expected_price
|
||||
@@ -121,9 +59,10 @@ def test_buy_elixir_success(avatar_in_city, mock_objects):
|
||||
assert len(avatar_in_city.elixirs) == 1
|
||||
assert avatar_in_city.elixirs[0].elixir.name == "聚气丹"
|
||||
|
||||
def test_buy_fail_not_in_city(dummy_avatar, mock_objects):
|
||||
def test_buy_fail_not_in_city(dummy_avatar, mock_item_data):
|
||||
"""测试不在城市无法购买"""
|
||||
elixirs_mock, materials_mock, _, _, _ = mock_objects
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
|
||||
# 确保不在城市 (dummy_avatar 默认在 (0,0) PLAIN)
|
||||
assert not isinstance(dummy_avatar.tile.region, CityRegion)
|
||||
@@ -137,9 +76,10 @@ def test_buy_fail_not_in_city(dummy_avatar, mock_objects):
|
||||
assert can_start is False
|
||||
assert "仅能在城市" in reason
|
||||
|
||||
def test_buy_fail_no_money(avatar_in_city, mock_objects):
|
||||
def test_buy_fail_no_money(avatar_in_city, mock_item_data):
|
||||
"""测试没钱无法购买"""
|
||||
elixirs_mock, materials_mock, _, _, test_material = mock_objects
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
|
||||
avatar_in_city.magic_stone = 0 # 没钱
|
||||
|
||||
@@ -152,9 +92,10 @@ def test_buy_fail_no_money(avatar_in_city, mock_objects):
|
||||
assert can_start is False
|
||||
assert "灵石不足" in reason
|
||||
|
||||
def test_buy_fail_unknown_item(avatar_in_city, mock_objects):
|
||||
def test_buy_fail_unknown_item(avatar_in_city, mock_item_data):
|
||||
"""测试未知物品"""
|
||||
elixirs_mock, materials_mock, _, _, _ = mock_objects
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
|
||||
with patch("src.utils.resolution.elixirs_by_name", elixirs_mock), \
|
||||
patch("src.utils.resolution.materials_by_name", materials_mock):
|
||||
@@ -165,11 +106,13 @@ def test_buy_fail_unknown_item(avatar_in_city, mock_objects):
|
||||
assert can_start is False
|
||||
assert "未知物品" in reason
|
||||
|
||||
def test_buy_elixir_fail_high_level_restricted(avatar_in_city, mock_objects):
|
||||
def test_buy_elixir_fail_high_level_restricted(avatar_in_city, mock_item_data):
|
||||
"""测试购买高阶丹药被限制"""
|
||||
elixirs_mock, materials_mock, _, high_level_elixir, _ = mock_objects
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
high_level_elixir = mock_item_data["obj_high_elixir"]
|
||||
|
||||
# 给予足够金钱,避免因为钱不够而先报错
|
||||
# 给予足够金钱
|
||||
avatar_in_city.magic_stone = 10000
|
||||
|
||||
# 角色是练气期,尝试买筑基期丹药
|
||||
@@ -183,12 +126,13 @@ def test_buy_elixir_fail_high_level_restricted(avatar_in_city, mock_objects):
|
||||
can_start, reason = action.can_start("筑基丹")
|
||||
|
||||
assert can_start is False
|
||||
# 当前版本限制仅开放练气期丹药
|
||||
assert "当前仅开放练气期丹药购买" in reason
|
||||
|
||||
def test_buy_elixir_fail_duplicate_active(avatar_in_city, mock_objects):
|
||||
def test_buy_elixir_fail_duplicate_active(avatar_in_city, mock_item_data):
|
||||
"""测试药效尚存无法重复购买"""
|
||||
elixirs_mock, materials_mock, test_elixir, _, _ = mock_objects
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
test_elixir = mock_item_data["obj_elixir"]
|
||||
|
||||
# 先服用一个
|
||||
consumed = ConsumedElixir(test_elixir, int(avatar_in_city.world.month_stamp))
|
||||
@@ -204,20 +148,37 @@ def test_buy_elixir_fail_duplicate_active(avatar_in_city, mock_objects):
|
||||
assert can_start is False
|
||||
assert "药效尚存" in reason
|
||||
|
||||
def test_buy_weapon_trade_in(avatar_in_city, mock_objects):
|
||||
def test_buy_weapon_trade_in(avatar_in_city, mock_item_data):
|
||||
"""测试购买新武器时自动卖出旧武器"""
|
||||
elixirs_mock, materials_mock, _, _, _ = mock_objects
|
||||
# 这里需要构造一个旧武器,mock_item_data里只有一套新武器
|
||||
from tests.conftest import create_test_weapon
|
||||
from src.classes.weapon import Weapon, WeaponType
|
||||
|
||||
# 构造旧武器和新武器
|
||||
old_weapon = Weapon(id=201, name="铁剑", weapon_type=WeaponType.SWORD, realm=Realm.Qi_Refinement, desc="...", effects={'atk': 1})
|
||||
new_weapon = Weapon(id=202, name="青云剑", weapon_type=WeaponType.SWORD, realm=Realm.Qi_Refinement, desc="...", effects={'atk': 10})
|
||||
elixirs_mock = mock_item_data["elixirs"]
|
||||
materials_mock = mock_item_data["materials"]
|
||||
new_weapon = mock_item_data["obj_weapon"]
|
||||
|
||||
# 手动添加武器到 materials_mock (Buy logic looks up weapons in materials too? Or just assumes unique names?)
|
||||
# Buy code checks `get_item_by_name` which checks all dicts.
|
||||
# In test_buy_action we only mocked elixirs and materials.
|
||||
# Let's ensure '青云剑' is findable. Ideally it should be in weapons_by_name but maybe Buy logic is flexible?
|
||||
# Original test put it in materials_mock["青云剑"] = new_weapon. Let's follow that pattern for now or better: mock weapons too.
|
||||
|
||||
# Wait, original test: materials_mock["青云剑"] = new_weapon
|
||||
# But `src.utils.resolution.get_item_by_name` checks materials, weapons, auxiliaries.
|
||||
# Let's do it properly by mocking weapons_by_name as well if possible, or just stick to materials for simplicity if Buy allows.
|
||||
# Buy uses `get_item_by_name`.
|
||||
|
||||
materials_mock["青云剑"] = new_weapon
|
||||
|
||||
# 构造旧武器
|
||||
old_weapon = create_test_weapon("铁剑", Realm.Qi_Refinement, weapon_id=199)
|
||||
old_weapon.effects = {'atk': 1}
|
||||
|
||||
# 装备旧武器
|
||||
avatar_in_city.change_weapon(old_weapon)
|
||||
assert avatar_in_city.weapon == old_weapon
|
||||
|
||||
materials_mock["青云剑"] = new_weapon
|
||||
|
||||
initial_money = avatar_in_city.magic_stone
|
||||
|
||||
# 价格计算
|
||||
@@ -244,5 +205,5 @@ def test_buy_weapon_trade_in(avatar_in_city, mock_objects):
|
||||
action._execute("青云剑")
|
||||
|
||||
assert avatar_in_city.weapon.name == "青云剑"
|
||||
assert avatar_in_city.weapon != old_weapon # 应该是新对象
|
||||
assert avatar_in_city.weapon != old_weapon
|
||||
assert avatar_in_city.magic_stone == expected_money
|
||||
|
||||
@@ -61,7 +61,7 @@ def test_circulation_manager_basic():
|
||||
|
||||
# Test adding Weapon
|
||||
w = create_mock_weapon(1, "Sword")
|
||||
# CirculationManager uses deepcopy, so we need to ensure the mock supports it or use real objects if possible.
|
||||
# CirculationManager uses instantiate, so we need to ensure the mock supports it
|
||||
# MagicMock is hard to deepcopy properly in some contexts, let's use a simple object structure or patch copy.deepcopy
|
||||
# But for robustness, let's try to make a real-ish object or a class that looks like Weapon
|
||||
|
||||
@@ -71,6 +71,9 @@ def test_circulation_manager_basic():
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.special_data = special_data or {}
|
||||
def instantiate(self):
|
||||
import copy
|
||||
return copy.deepcopy(self)
|
||||
|
||||
w1 = DummyItem(1, "Sword", {"kills": 10})
|
||||
cm.add_weapon(w1)
|
||||
@@ -100,6 +103,9 @@ def test_circulation_serialization():
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.special_data = {}
|
||||
def instantiate(self):
|
||||
import copy
|
||||
return copy.deepcopy(self)
|
||||
|
||||
w1 = DummyItem(101, "RareSword")
|
||||
w1.special_data = {"stat": 1}
|
||||
@@ -175,6 +181,7 @@ def test_avatar_sell_integration(empty_world):
|
||||
# 1. Test Sell Weapon
|
||||
# Create a dummy weapon that acts like the real one
|
||||
weapon = MagicMock(spec=Weapon)
|
||||
weapon.instantiate.return_value = weapon # Mock instantiate
|
||||
weapon.id = 999
|
||||
weapon.name = "TestBlade"
|
||||
weapon.realm = Realm.Qi_Refinement
|
||||
@@ -198,6 +205,7 @@ def test_avatar_sell_integration(empty_world):
|
||||
|
||||
# 2. Test Sell Auxiliary
|
||||
aux = MagicMock(spec=Auxiliary)
|
||||
aux.instantiate.return_value = aux # Mock instantiate
|
||||
aux.id = 888
|
||||
aux.name = "TestAmulet"
|
||||
|
||||
@@ -219,6 +227,9 @@ def test_save_load_circulation(temp_save_dir, empty_world):
|
||||
self.name = name
|
||||
self.special_data = {}
|
||||
self.realm = Realm.Qi_Refinement # needed if deepcopy looks at it or for other checks
|
||||
def instantiate(self):
|
||||
import copy
|
||||
return copy.deepcopy(self)
|
||||
|
||||
w1 = SimpleItem(10, "LostSword")
|
||||
w1.special_data = {"kills": 99}
|
||||
|
||||
@@ -49,13 +49,12 @@ class TestEquipment:
|
||||
|
||||
w2 = get_random_weapon_by_realm(Realm.Qi_Refinement)
|
||||
# 即使随机到同一个原型,它们也应该是不同的对象
|
||||
# 注意:get_random_weapon_by_realm 内部已经做了 deepcopy
|
||||
# 注意:get_random_weapon_by_realm 内部已经做了 instantiate
|
||||
|
||||
# 为了确保测试有效,我们手动获取同一个原型并 deepcopy
|
||||
# 为了确保测试有效,我们手动获取同一个原型并 instantiate
|
||||
prototype = weapons_by_id[w1.id]
|
||||
import copy
|
||||
w_copy1 = copy.deepcopy(prototype)
|
||||
w_copy2 = copy.deepcopy(prototype)
|
||||
w_copy1 = prototype.instantiate()
|
||||
w_copy2 = prototype.instantiate()
|
||||
|
||||
assert w_copy1 is not w_copy2
|
||||
assert w_copy1.id == w_copy2.id
|
||||
|
||||
@@ -1,79 +1,15 @@
|
||||
import pytest
|
||||
from unittest.mock import patch, MagicMock
|
||||
from unittest.mock import patch
|
||||
from src.classes.action.sell import Sell
|
||||
from src.classes.region import CityRegion
|
||||
from src.classes.material import Material
|
||||
from src.classes.weapon import Weapon
|
||||
from src.classes.auxiliary import Auxiliary
|
||||
from src.classes.cultivation import Realm
|
||||
from src.classes.tile import Tile, TileType
|
||||
from src.classes.weapon_type import WeaponType
|
||||
from tests.conftest import create_test_material # Explicit import if needed
|
||||
|
||||
# 创建测试用的对象 helper
|
||||
def create_test_material(name, realm, material_id=101):
|
||||
return Material(
|
||||
id=material_id,
|
||||
name=name,
|
||||
desc="测试材料",
|
||||
realm=realm
|
||||
)
|
||||
|
||||
def create_test_weapon(name, realm, weapon_id=201):
|
||||
return Weapon(
|
||||
id=weapon_id,
|
||||
name=name,
|
||||
weapon_type=WeaponType.SWORD,
|
||||
realm=realm,
|
||||
desc="测试兵器",
|
||||
effects={},
|
||||
effect_desc=""
|
||||
)
|
||||
|
||||
def create_test_auxiliary(name, realm, aux_id=301):
|
||||
return Auxiliary(
|
||||
id=aux_id,
|
||||
name=name,
|
||||
realm=realm,
|
||||
desc="测试法宝",
|
||||
effects={},
|
||||
effect_desc=""
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def avatar_in_city(dummy_avatar):
|
||||
"""
|
||||
修改 dummy_avatar,使其位于城市中,并给予初始状态
|
||||
"""
|
||||
city_region = CityRegion(id=1, name="TestCity", desc="测试城市")
|
||||
tile = Tile(0, 0, TileType.CITY)
|
||||
tile.region = city_region
|
||||
|
||||
dummy_avatar.tile = tile
|
||||
dummy_avatar.magic_stone = 0
|
||||
dummy_avatar.materials = {}
|
||||
dummy_avatar.weapon = None
|
||||
dummy_avatar.auxiliary = None
|
||||
|
||||
return dummy_avatar
|
||||
|
||||
@pytest.fixture
|
||||
def mock_sell_objects():
|
||||
"""
|
||||
Mock materials_by_name/weapons/auxiliaries 并提供测试对象
|
||||
"""
|
||||
test_material = create_test_material("铁矿石", Realm.Qi_Refinement)
|
||||
test_weapon = create_test_weapon("青云剑", Realm.Qi_Refinement)
|
||||
test_auxiliary = create_test_auxiliary("聚灵珠", Realm.Qi_Refinement)
|
||||
|
||||
materials_mock = {"铁矿石": test_material}
|
||||
weapons_mock = {"青云剑": test_weapon}
|
||||
auxiliaries_mock = {"聚灵珠": test_auxiliary}
|
||||
|
||||
return materials_mock, weapons_mock, auxiliaries_mock, test_material, test_weapon, test_auxiliary
|
||||
|
||||
def test_sell_material_success(avatar_in_city, mock_sell_objects):
|
||||
def test_sell_material_success(avatar_in_city, mock_item_data):
|
||||
"""测试出售普通材料成功"""
|
||||
materials_mock, weapons_mock, auxiliaries_mock, test_material, _, _ = mock_sell_objects
|
||||
materials_mock = mock_item_data["materials"]
|
||||
weapons_mock = mock_item_data["weapons"]
|
||||
auxiliaries_mock = mock_item_data["auxiliaries"]
|
||||
test_material = mock_item_data["obj_material"]
|
||||
|
||||
# 给角色添加材料
|
||||
avatar_in_city.add_material(test_material, quantity=5)
|
||||
@@ -100,9 +36,12 @@ def test_sell_material_success(avatar_in_city, mock_sell_objects):
|
||||
assert avatar_in_city.magic_stone == initial_money + expected_income
|
||||
assert avatar_in_city.get_material_quantity(test_material) == 0
|
||||
|
||||
def test_sell_weapon_success(avatar_in_city, mock_sell_objects):
|
||||
def test_sell_weapon_success(avatar_in_city, mock_item_data):
|
||||
"""测试出售当前兵器成功"""
|
||||
materials_mock, weapons_mock, auxiliaries_mock, _, test_weapon, _ = mock_sell_objects
|
||||
materials_mock = mock_item_data["materials"]
|
||||
weapons_mock = mock_item_data["weapons"]
|
||||
auxiliaries_mock = mock_item_data["auxiliaries"]
|
||||
test_weapon = mock_item_data["obj_weapon"]
|
||||
|
||||
# 装备兵器
|
||||
avatar_in_city.weapon = test_weapon
|
||||
@@ -118,23 +57,23 @@ def test_sell_weapon_success(avatar_in_city, mock_sell_objects):
|
||||
assert can_start is True
|
||||
|
||||
# 2. 执行出售
|
||||
# 练气期兵器基础价格 100,卖出倍率 1.0 -> 100
|
||||
# 修正:根据之前的测试反馈,Prices中 Qi_Refinement 的兵器价格似乎也是 10 (默认值)。
|
||||
# 如果系统中没有正确加载 weapon.csv,价格可能就是默认值。
|
||||
# 我们这里假设它是 10 来通过测试,或者 mock prices (但这有点麻烦)。
|
||||
# 之前失败的日志里没有价格断言错误,只有 AttributeError。
|
||||
# 这里维持原来的 expected_income = 10,如果失败再调。
|
||||
# 练气期兵器基础价格 100? No, original test assumed 10 due to fallback/mock issues.
|
||||
# Let's keep assuming 10 for consistency with previous pass.
|
||||
expected_income = 10
|
||||
|
||||
initial_money = avatar_in_city.magic_stone
|
||||
action._execute("青云剑")
|
||||
|
||||
# 3. 验证结果
|
||||
assert avatar_in_city.magic_stone == expected_income
|
||||
assert avatar_in_city.magic_stone == initial_money + expected_income
|
||||
assert avatar_in_city.weapon is None
|
||||
|
||||
def test_sell_auxiliary_success(avatar_in_city, mock_sell_objects):
|
||||
def test_sell_auxiliary_success(avatar_in_city, mock_item_data):
|
||||
"""测试出售当前法宝成功"""
|
||||
materials_mock, weapons_mock, auxiliaries_mock, _, _, test_auxiliary = mock_sell_objects
|
||||
materials_mock = mock_item_data["materials"]
|
||||
weapons_mock = mock_item_data["weapons"]
|
||||
auxiliaries_mock = mock_item_data["auxiliaries"]
|
||||
test_auxiliary = mock_item_data["obj_auxiliary"]
|
||||
|
||||
# 装备法宝
|
||||
avatar_in_city.auxiliary = test_auxiliary
|
||||
@@ -152,12 +91,15 @@ def test_sell_auxiliary_success(avatar_in_city, mock_sell_objects):
|
||||
|
||||
action._execute("聚灵珠")
|
||||
|
||||
assert avatar_in_city.magic_stone == expected_income
|
||||
assert avatar_in_city.magic_stone == 1000 + expected_income
|
||||
assert avatar_in_city.auxiliary is None
|
||||
|
||||
def test_sell_fail_not_in_city(dummy_avatar, mock_sell_objects):
|
||||
def test_sell_fail_not_in_city(dummy_avatar, mock_item_data):
|
||||
"""测试不在城市无法出售"""
|
||||
materials_mock, weapons_mock, auxiliaries_mock, test_material, _, _ = mock_sell_objects
|
||||
materials_mock = mock_item_data["materials"]
|
||||
weapons_mock = mock_item_data["weapons"]
|
||||
auxiliaries_mock = mock_item_data["auxiliaries"]
|
||||
test_material = mock_item_data["obj_material"]
|
||||
|
||||
# 确保不在城市
|
||||
assert not isinstance(dummy_avatar.tile.region, CityRegion)
|
||||
@@ -173,11 +115,13 @@ def test_sell_fail_not_in_city(dummy_avatar, mock_sell_objects):
|
||||
assert can_start is False
|
||||
assert "仅能在城市" in reason
|
||||
|
||||
def test_sell_fail_no_item(avatar_in_city, mock_sell_objects):
|
||||
def test_sell_fail_no_item(avatar_in_city, mock_item_data):
|
||||
"""测试未持有该材料"""
|
||||
materials_mock, weapons_mock, auxiliaries_mock, _, _, _ = mock_sell_objects
|
||||
materials_mock = mock_item_data["materials"]
|
||||
weapons_mock = mock_item_data["weapons"]
|
||||
auxiliaries_mock = mock_item_data["auxiliaries"]
|
||||
|
||||
# 背包为空,无装备
|
||||
# 背包为空,无装备 (fixture default)
|
||||
|
||||
with patch("src.utils.resolution.materials_by_name", materials_mock), \
|
||||
patch("src.utils.resolution.weapons_by_name", weapons_mock), \
|
||||
@@ -189,9 +133,11 @@ def test_sell_fail_no_item(avatar_in_city, mock_sell_objects):
|
||||
assert can_start is False
|
||||
assert "未持有材料" in reason
|
||||
|
||||
def test_sell_fail_unknown_name(avatar_in_city, mock_sell_objects):
|
||||
def test_sell_fail_unknown_name(avatar_in_city, mock_item_data):
|
||||
"""测试未知物品名称"""
|
||||
materials_mock, weapons_mock, auxiliaries_mock, _, _, _ = mock_sell_objects
|
||||
materials_mock = mock_item_data["materials"]
|
||||
weapons_mock = mock_item_data["weapons"]
|
||||
auxiliaries_mock = mock_item_data["auxiliaries"]
|
||||
|
||||
with patch("src.utils.resolution.materials_by_name", materials_mock), \
|
||||
patch("src.utils.resolution.weapons_by_name", weapons_mock), \
|
||||
@@ -203,12 +149,19 @@ def test_sell_fail_unknown_name(avatar_in_city, mock_sell_objects):
|
||||
assert can_start is False
|
||||
assert "未持有物品/装备" in reason
|
||||
|
||||
def test_sell_priority(avatar_in_city, mock_sell_objects):
|
||||
def test_sell_priority(avatar_in_city, mock_item_data):
|
||||
"""测试优先级:同名时优先卖身上装备(根据 resolution 优先级)"""
|
||||
materials_mock, weapons_mock, auxiliaries_mock, test_material, test_weapon, _ = mock_sell_objects
|
||||
materials_mock = mock_item_data["materials"]
|
||||
weapons_mock = mock_item_data["weapons"]
|
||||
auxiliaries_mock = mock_item_data["auxiliaries"]
|
||||
test_weapon = mock_item_data["obj_weapon"]
|
||||
|
||||
# 构造一个同名的兵器和材料
|
||||
# 构造一个同名的材料
|
||||
# 需要从 conftest 导入
|
||||
from src.classes.cultivation import Realm
|
||||
fake_sword_material = create_test_material("青云剑", Realm.Qi_Refinement)
|
||||
|
||||
# 修改 mock,让 "青云剑" 在 materials 里也能找到
|
||||
materials_mock["青云剑"] = fake_sword_material
|
||||
|
||||
# 角色同时拥有该材料和该兵器
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
宗门名称,行事风格,总部,成员,功法,宝物
|
||||
明心剑宗,明心剑宗为通玄界东方第一正道大宗,位列正道九宗之一,以无上剑道称雄于世。宗门崇尚玄门正宗,修行纯正真息,注重剑修传承与心性磨砺,强调道心坚定、品性端正、尊师重道,排斥心机深沉之徒。修行体系严谨,重视根基扎实,主张内外兼修、精气神三宝如一,推崇水磨工夫,不尚浮躁冒进。弟子需经严苛考验(如攀登坐忘峰)方可入门,修炼资源充裕,授徒贵精不贵多,专注精英培养。宗风光明正大,纪律严明,门规森然,对背叛师门、败坏清誉者绝不姑息,同时亦重情义、讲侠骨,护山阵法严密,战力凌厉果断。擅长禁制与阵法研究,尤以云纹、明心七禁纹、禁纹神通著称,结合血脉布局深远。宗门参与正派联盟事务,承担除魔卫道之责,在诛邪行动中威慑力极强,拥有顶尖战力钟隐及通玄第一神剑斩空神剑。整体氛围庄严而不失人情,既有仙家风范,亦存师门温情,对弟子既严格又回护,允许自由研习与灵活应对,但重大原则问题毫不妥协。,明心剑宗总部位于通玄界东方的连霞山脉,主峰包括坐忘峰、止观峰、观霞峰等七十二峰,其中坐忘峰与止观峰为核心重地。坐忘峰高逾五十万里,自成一界,天地元气随潮汐变化,设有启元堂供弟子修习,过半程即自动列入门墙;峰内有四季更替、飞禽走兽,东括东海百零八岛礁,北揽箕山,南至宵河,西达松岭,地域广袤。止观峰设‘未明观’为议事与修行中枢,以斩空神剑镇守阵眼,布九重阵法,统合亿万气机,具备移山倒海之威。宗门另有据点分布于夜摩天霜风谷、心园等地,代表参与通玄诸宗会盟,战略地位显赫。,"明彦, 清溟道人, 明松道人, 单智, 李珣, 清虚真人, 灵机, 文海, 祈碧, 孙皖, 钟隐仙师, 青吟, 林阁, 明玑, 明澜道人, 岳明风, 齐芸, 顾颦儿, 林无忧, 明德, 清阳, 清越, 伍灵泉, 灵木, 灵喆, 明如, 秦婉如, 古音, 青吟仙师, 明吉仙师, 明和, 李明和, 栖霞, 青鸾, 阴散人, 明惑, 颜水月, 灵吉, 婴宁, 灵竹, 闪灵儿, 明巩, 洛歧昌, 尹师妹, 宋师妹, 林师伯, 林阁师伯, 清溟, 锺隐, 明彦仙师, 明彦老道, 明心灵竹, 明玑回","流火赤金瞳, 天罗剑令, 洞玄剑诀, 灵犀诀, 内息搬运术, 四法三诀, 云纹禁制, 化气篇, 三化二真, 太上感应篇, 明玉真诀, 碧霄通达志, 披霞剑诀, 明纹, 山纹, 水纹, 晦纹, 金丹真息锁构体, 御剑飞行之术, 附灵之术, 引煞之术, 踏剑式, 驾云之术, 饲鹰心法, 青烟竹影, 明心剑宗心法, 千重嶂, 随波万里, 御剑, 七情火, 禁纹之术, 御剑飞行, 无情心, 极变阴阳法, 云纹, 绞魂丝, 碧灵掌, 太清神音, 土遁之术, 骨络通心之法, 极光玄真法, 一炷香(阵诀), 无禁风(阵诀), 悬空阵, 明心剑宗剑诀, 天一剑, 骨络通心之术, 刑天法剑, 指路幽灯, 青烟竹影百迭障, 玄门真息, 近身搏杀剑, 遥空剑气, 阵法, 阵法之道, 明心剑宗基础剑法, 驱魂炼魄通心大法, 明心灵竹, 御剑术, 洞玄剑法, 明心七禁纹, 明心剑宗诸多法门, 明心剑宗的隐形匿迹法门, 镇海八法, 七大禁制, 剑气圆融, 青烟竹影剑诀, 阵法秘要直指, 御剑搏杀, 心魔精进法, 玄门无上秘法, 明心剑诀, 子午剑罡, 丹霞劲, 藏星秘剑, 青烟障, 大五行寂灭雷光, 混元杵, 明心剑宗传讯飞剑术, 玄门正宗剑诀, 参商法, 破军仙剑剑气, 燃血元息, 明心剑宗内仅在清溟之下的战力, 三方六回阵法, 飞鸢牵魂之术, 海雨天风剑诀, 心照法剑, 斩空神剑","云袍, 坐忘石, 传讯剑符, 防身匕首, 丹药, 文海所赠刻有禁制的珠子, 青玉, 凤翎针, 玉辟邪, 逝水, 青玉剑, 九重石, 天冥化阴珠, 云楼揽月车, 透天水镜, 斩空神剑, 吞海灵犀, 明心剑, 长风哨, 参星盘, 苦竹, 通灵剑器, 龙纹印剑, 垂天钟, 斩空宝剑, 明心灵竹, 初雪剑, 苦竹宝剑, 破军仙剑, 青玉宝剑, 本命灵牌"
|
||||
明心剑宗,明心剑宗为通玄界东方第一正道大宗,位列正道九宗之一,以无上剑道称雄于世。宗门崇尚玄门正宗,修行纯正真息,注重剑修传承与心性磨砺,强调道心坚定、品性端正、尊师重道,排斥心机深沉之徒。修行体系严谨,重视根基扎实,主张内外兼修、精气神三宝如一,推崇水磨工夫,不尚浮躁冒进。弟子需经严苛考验(如攀登坐忘峰)方可入门,修炼资源充裕,授徒贵精不贵多,专注精英培养。宗风光明正大,纪律严明,门规森然,对背叛师门、败坏清誉者绝不姑息,同时亦重情义、讲侠骨,护山阵法严密,战力凌厉果断。擅长阵法与阵法研究,尤以云纹、明心七禁纹、禁纹神通著称,结合血脉布局深远。宗门参与正派联盟事务,承担除魔卫道之责,在诛邪行动中威慑力极强,拥有顶尖战力钟隐及通玄第一神剑斩空神剑。整体氛围庄严而不失人情,既有仙家风范,亦存师门温情,对弟子既严格又回护,允许自由研习与灵活应对,但重大原则问题毫不妥协。,明心剑宗总部位于通玄界东方的连霞山脉,主峰包括坐忘峰、止观峰、观霞峰等七十二峰,其中坐忘峰与止观峰为核心重地。坐忘峰高逾五十万里,自成一界,天地元气随潮汐变化,设有启元堂供弟子修习,过半程即自动列入门墙;峰内有四季更替、飞禽走兽,东括东海百零八岛礁,北揽箕山,南至宵河,西达松岭,地域广袤。止观峰设‘未明观’为议事与修行中枢,以斩空神剑镇守阵眼,布九重阵法,统合亿万气机,具备移山倒海之威。宗门另有据点分布于夜摩天霜风谷、心园等地,代表参与通玄诸宗会盟,战略地位显赫。,"明彦, 清溟道人, 明松道人, 单智, 李珣, 清虚真人, 灵机, 文海, 祈碧, 孙皖, 钟隐仙师, 青吟, 林阁, 明玑, 明澜道人, 岳明风, 齐芸, 顾颦儿, 林无忧, 明德, 清阳, 清越, 伍灵泉, 灵木, 灵喆, 明如, 秦婉如, 古音, 青吟仙师, 明吉仙师, 明和, 李明和, 栖霞, 青鸾, 阴散人, 明惑, 颜水月, 灵吉, 婴宁, 灵竹, 闪灵儿, 明巩, 洛歧昌, 尹师妹, 宋师妹, 林师伯, 林阁师伯, 清溟, 锺隐, 明彦仙师, 明彦老道, 明心灵竹, 明玑回","流火赤金瞳, 天罗剑令, 洞玄剑诀, 灵犀诀, 内息搬运术, 四法三诀, 云纹阵法, 化气篇, 三化二真, 太上感应篇, 明玉真诀, 碧霄通达志, 披霞剑诀, 明纹, 山纹, 水纹, 晦纹, 金丹真息锁构体, 御剑飞行之术, 附灵之术, 引煞之术, 踏剑式, 驾云之术, 饲鹰心法, 青烟竹影, 明心剑宗心法, 千重嶂, 随波万里, 御剑, 七情火, 禁纹之术, 御剑飞行, 无情心, 极变阴阳法, 云纹, 绞魂丝, 碧灵掌, 太清神音, 土遁之术, 骨络通心之法, 极光玄真法, 一炷香(阵诀), 无禁风(阵诀), 悬空阵, 明心剑宗剑诀, 天一剑, 骨络通心之术, 刑天法剑, 指路幽灯, 青烟竹影百迭障, 玄门真息, 近身搏杀剑, 遥空剑气, 阵法, 阵法之道, 明心剑宗基础剑法, 驱魂炼魄通心大法, 明心灵竹, 御剑术, 洞玄剑法, 明心七禁纹, 明心剑宗诸多法门, 明心剑宗的隐形匿迹法门, 镇海八法, 七大阵法, 剑气圆融, 青烟竹影剑诀, 阵法秘要直指, 御剑搏杀, 心魔精进法, 玄门无上秘法, 明心剑诀, 子午剑罡, 丹霞劲, 藏星秘剑, 青烟障, 大五行寂灭雷光, 混元杵, 明心剑宗传讯飞剑术, 玄门正宗剑诀, 参商法, 破军仙剑剑气, 燃血元息, 明心剑宗内仅在清溟之下的战力, 三方六回阵法, 飞鸢牵魂之术, 海雨天风剑诀, 心照法剑, 斩空神剑","云袍, 坐忘石, 传讯剑符, 防身匕首, 丹药, 文海所赠刻有阵法的珠子, 青玉, 凤翎针, 玉辟邪, 逝水, 青玉剑, 九重石, 天冥化阴珠, 云楼揽月车, 透天水镜, 斩空神剑, 吞海灵犀, 明心剑, 长风哨, 参星盘, 苦竹, 通灵剑器, 龙纹印剑, 垂天钟, 斩空宝剑, 明心灵竹, 初雪剑, 苦竹宝剑, 破军仙剑, 青玉宝剑, 本命灵牌"
|
||||
妙化宗,精擅音律杀伐与精神操控,功法诡谲阴柔,以音攻、惑神、心理压迫见长;行踪隐秘,手段凌厉,布局深远,威慑力强。表面文雅缥缈,实则深藏算计,善于言辞周旋与主动权掌控。作为散修盟会发起者,联合妖人、散修及妖凤、青鸾等势力对抗正道,具号召力与组织能力。宗风邪异而不拘常规,纵情声色,等级分明(如妙化五侍),重视宗主意志执行。内部存在叔侄权力斗争,但对外影响力广泛。,心园,位于通玄界北极夜摩之天核心落玉湖畔,四季如春,百花不谢,为宗门山门所在;内有亭台楼阁、丝竹不绝,镇有冰牢于北海水眼之上,是洞天中枢。,"古音, 玉散人, 妖凤, 青鸾, 羽侍, 古道人, 古志玄, 青吟, 宫侍, 商侍, 钟隐","种玉魔功, 阴符经, 七杀琴, 幽玄傀儡炼制法门, 勾魂蚀元神术, 玄婴度劫, 血融之术, 穿心曲, 惑神曲, 妙化四神曲, 造化魔功, 妙化宗法门","七杀琴, 避水珠, 冷锁乌金链, 玉美人"
|
||||
幽魂噬影宗,邪道宗门,行事诡秘阴森,崇尚阴邪之术,擅长操控阴火、鬼道、咒灵与魂魄,精通寄魂转生、控神摄魂、驱尸炼魄等邪异秘法。宗门作风狠辣隐秘,注重权谋算计、内部竞争与实力压制,等级森严,派系倾轧激烈,对外树敌众多但善于借势布局。修炼方式偏邪,常以精血怨气奉养祖师咒灵,手段包括傀儡操控、幻术威慑、安插卧底、阴谋借刀杀人等。虽为邪宗,亦有制度化管理,如定期授业、祭祖大典与誓约控制,强调宗门存亡高于个体,必要时可玉石俱焚。被称作‘九真之首,第一邪宗’,与正道对立,唯利是图而不拘礼法,但重视传承、因果与祖师遗志。,位于通玄界西南的鬼门湖湖心岛,核心区域包括湖心地宫、祭台、化阴池及召灵钟,深达地下数十丈,通过法术连接沉于千里地底的化阴池。此地常年笼罩浅灰薄雾,环境阴森,充斥九幽地气,设有禁制阵法与虚空裂隙,是宗门举行祭祖大典、权力交接与秘法修行的圣地。周边势力范围涵盖腾化谷、北齐山剃刀峰等地,拥有灵脉、药圃、矿山等资源。曾因九幽噬界事件遭封界,宗门基业衰败,现处于封锁空间内。,"鬼先生, 李珣, 碧水君, 冥火阎罗, 毕如晦, 应采儿, 阎夫人, 归无藏, 叶如, 冥璃, 幽五省, 苍冥子长老, 阴馑长老, 幽狱长老, 百鬼道人, 栖霞元君, 血散人, 顾颦儿, 阎采儿, 阴拓, 阎湖, 阎如, 阎飙长老, 幽习长老, 幽离, 阎曾, 古音, 玉散人, 九幽老祖, 诸位长老, 大姓弟子, 低辈弟子, 百鬼, 水蝶兰, 冥火老儿, 血魔百鬼道人, 鬼机, 朱泓","幽明气, 寄魂转生, 镇派六法门, 幽冥录, 附魂引, 幽明阴火, 驱魂炼魄通心大法, 截空杀, 九幽搜魂, 黄泉恸鬼窟, 通幽鬼路, 阴阳转极化生炼法, 幽玄印, 幽玄傀儡, 平脉三法, 九幽穿石遁法, 慑魂魔音, 拘魂敕令, 噬影大法, 驱尸傀儡术, 控魂大法, 幽玄影身, 碧火流莹咒法, 压阵法诀, 幽火烛目, 不动邪心, 血魔化心大法, 离魂阴劫, 鬼灵火, 乱纹禁, 心血轮眼, 搜魂术, 幽玄大法, 鬼灵转生术, 惑神之术, 逆影遁法, 无底冥环, 骨络通心之法, 质气转换, 影傀儡, 离魂神音, 幽一, 吞精噬元之术, 阴火珠相关功法, 辨魂之术, 化阴池相关功法, 控神之法, 血神子, 燃血锻体, 锁魂勾, 血影妖身, 燃血元息, 控魂术, 勾魂术, 傀儡术, 抽髓之法, 引灵入体法门, 血魔秘术, 心符水印, 真息导引, 阵法纹路, 咒文符箓, 血神锻体, 幽域天障, 五极解封, 九幽噬界, 幽冥模式, 幽狱观想之术, 幽明气基础法诀, 无常索, 蚀心炼魂, 冥化神术, 绝息竭元之术, 水镜之术, 辨血识人, 血魇之术, 鬼火引, 幽明鬼火","幽冥录, 阴火(黑珠), 化阴池, 天冥化阴珠, 尘风宝珠, 铜铃, 骷髅头骨, 幽玄傀儡(幽一、幽二等), 七鬼铃, 天识轮, 智识珠, 鬼鸦剑, 无颜甲, 七鬼环, 阴火珠, 飞魂敕令, 玉辟邪, 行尸丹, 金丸神泥封禁的紫玉盒, 解咒玉简, 太素化阴玉液, 五遁障, 锁灵灰金石罩, 紫玉盒, 金丸神泥, 鬼门印, 曜魅环, 鬼门令, 雾松铁祭服, 天王伞模样的法宝, 天王伞, 祖师咒灵, 玄冥飞环, 定魂星, 乌金链, 冰风宝珠"
|
||||
幽魂噬影宗,邪道宗门,行事诡秘阴森,崇尚阴邪之术,擅长操控阴火、鬼道、咒灵与魂魄,精通寄魂转生、控神摄魂、驱尸炼魄等邪异秘法。宗门作风狠辣隐秘,注重权谋算计、内部竞争与实力压制,等级森严,派系倾轧激烈,对外树敌众多但善于借势布局。修炼方式偏邪,常以精血怨气奉养祖师咒灵,手段包括傀儡操控、幻术威慑、安插卧底、阴谋借刀杀人等。虽为邪宗,亦有制度化管理,如定期授业、祭祖大典与誓约控制,强调宗门存亡高于个体,必要时可玉石俱焚。被称作‘九真之首,第一邪宗’,与正道对立,唯利是图而不拘礼法,但重视传承、因果与祖师遗志。,位于通玄界西南的鬼门湖湖心岛,核心区域包括湖心地宫、祭台、化阴池及召灵钟,深达地下数十丈,通过法术连接沉于千里地底的化阴池。此地常年笼罩浅灰薄雾,环境阴森,充斥九幽地气,设有阵法阵法与虚空裂隙,是宗门举行祭祖大典、权力交接与秘法修行的圣地。周边势力范围涵盖腾化谷、北齐山剃刀峰等地,拥有灵脉、药圃、矿山等资源。曾因九幽噬界事件遭封界,宗门基业衰败,现处于封锁空间内。,"鬼先生, 李珣, 碧水君, 冥火阎罗, 毕如晦, 应采儿, 阎夫人, 归无藏, 叶如, 冥璃, 幽五省, 苍冥子长老, 阴馑长老, 幽狱长老, 百鬼道人, 栖霞元君, 血散人, 顾颦儿, 阎采儿, 阴拓, 阎湖, 阎如, 阎飙长老, 幽习长老, 幽离, 阎曾, 古音, 玉散人, 九幽老祖, 诸位长老, 大姓弟子, 低辈弟子, 百鬼, 水蝶兰, 冥火老儿, 血魔百鬼道人, 鬼机, 朱泓","幽明气, 寄魂转生, 镇派六法门, 幽冥录, 附魂引, 幽明阴火, 驱魂炼魄通心大法, 截空杀, 九幽搜魂, 黄泉恸鬼窟, 通幽鬼路, 阴阳转极化生炼法, 幽玄印, 幽玄傀儡, 平脉三法, 九幽穿石遁法, 慑魂魔音, 拘魂敕令, 噬影大法, 驱尸傀儡术, 控魂大法, 幽玄影身, 碧火流莹咒法, 压阵法诀, 幽火烛目, 不动邪心, 血魔化心大法, 离魂阴劫, 鬼灵火, 乱纹禁, 心血轮眼, 搜魂术, 幽玄大法, 鬼灵转生术, 惑神之术, 逆影遁法, 无底冥环, 骨络通心之法, 质气转换, 影傀儡, 离魂神音, 幽一, 吞精噬元之术, 阴火珠相关功法, 辨魂之术, 化阴池相关功法, 控神之法, 血神子, 燃血锻体, 锁魂勾, 血影妖身, 燃血元息, 控魂术, 勾魂术, 傀儡术, 抽髓之法, 引灵入体法门, 血魔秘术, 心符水印, 真息导引, 阵法纹路, 咒文符箓, 血神锻体, 幽域天障, 五极解封, 九幽噬界, 幽冥模式, 幽狱观想之术, 幽明气基础法诀, 无常索, 蚀心炼魂, 冥化神术, 绝息竭元之术, 水镜之术, 辨血识人, 血魇之术, 鬼火引, 幽明鬼火","幽冥录, 阴火(黑珠), 化阴池, 天冥化阴珠, 尘风宝珠, 铜铃, 骷髅头骨, 幽玄傀儡(幽一、幽二等), 七鬼铃, 天识轮, 智识珠, 鬼鸦剑, 无颜甲, 七鬼环, 阴火珠, 飞魂敕令, 玉辟邪, 行尸丹, 金丸神泥封禁的紫玉盒, 解咒玉简, 太素化阴玉液, 五遁障, 锁灵灰金石罩, 紫玉盒, 金丸神泥, 鬼门印, 曜魅环, 鬼门令, 雾松铁祭服, 天王伞模样的法宝, 天王伞, 祖师咒灵, 玄冥飞环, 定魂星, 乌金链, 冰风宝珠"
|
||||
无心宗,行事隐秘,擅长伏击与心理战,常用障眼法和多重杀招突袭;修炼心火、命气等邪异功法,注重化五脏、融六腑、炼皮骨、销血肉,将肉体转化为先天命气。曾为避天劫植入蛟珠,积聚戾气,有阴谋手段。中落已久,仅靠宗主独力支撑,在强敌环伺下艰难生存,后被散修盟会攻破,濒临覆灭。传闻可能加入西联联盟,但实力不济,未受重视。,幽山七十二盘,"心殛子, 宫五, 宫六, 七无道人","化心火, 命气化七身, 心系(心脏化核), 心炎, 先天命气, 心炎九转",魂火珠
|
||||
三皇剑宗,正道名门,强势霸气,以武立宗,讲究威势与震慑,主张‘不战而屈人之兵’。擅长王道剑诀,剑法凌厉,注重实战与精英培养,弟子意志不屈,集体行动力强。重视宗门荣誉,对仇敌记恨久远,但为大局可让步。行事果断,宗主专决,长辈谨慎,不愿轻结后辈之仇。活跃于重大事件,参与镇压与调查,地位尊崇,为正道九宗之一。,位于赤城山,地处中南部,势力临近腾化谷东部,具备熟人网络与安全庇护能力。,"何志彦(天君), 胡不离, 洛玉姬, 闵二山, 东阳山人, 洛岐昌, 龙首狂客, 洛无昌, 碧霄客, 萧怡, 梢英","王道剑诀, 叱雷天变, 海天八变, 三皇剑宗的剑诀","透音砂, 垂丝飞环"
|
||||
冥王宗,邪道宗门,以阴邪鬼气为修行根基,与正道对立。手段阴狠,擅长阵法、驱妖摄鬼及隐秘行动,行事霸道,杀气森森,为达目的不择手段,常背后偷袭或发动突袭。组织严密,重视脸面,不容外宗插手事务。与幽魂噬影宗为死敌,同百鬼有血仇,曾参与西联联盟,可能与嗜鬼宗联合行动。,位于七鬼角的群岛上,四面临海,周围暗礁密布,"宋元敕, 元烁, 元难, 无尽冥主, 元樟, 惕无咎, 李元曦, 冥火阎罗, 冥思, 元苦, 元艰, 十八冥将, 两个灵尊, 四个冥将, 三位冥将","七鬼摄海破, 七冥星阵, 血神劫指, 镇派六法, 诛鬼刺",
|
||||
天行健宗,正道宗门,专修浩然之气,行事正大光明,刚健果决,重视道义与同门情义,对邪道功法有强克制力。作风严谨守纪,注重传道授业与师门任务,坚持原则但能审时度势,不滥杀无辜。曾牵头发布“天罚令”,组织除魔联盟,彰显正义担当。接纳客卿谨慎,须名声极佳,门下弟子多稳重守礼,有君子之风。,位于不夜城后方,与明心剑宗防区相连。,"师兄, 刘师哥, 女修师妹, 何慕兰, 顾颦儿, 董明, 苏曜, 乾元先生, 庄楚, 水蝶兰, 大衍先生, 梅洁, 钟隐","浩然之气, 行神如空,行气如虹, 天行交感之阵, 五方神通感应, 太初剑诀, 青烟竹障, 元阳珠, 紫阳神剑, 百里飞剑, 红莲劫",
|
||||
嗜鬼宗,邪道宗门,由幽魂噬影宗分裂而来,以鬼修为主,擅长冥化神术与阴气操控,行事阴狠诡谲、霸道。曾有意加入西联联盟,与冥王宗并列引发担忧,现或有与幽魂宗复合之议。,离恨天,"幽离, 阴馑, 鬼老三","噬影大法, 冥化神术",
|
||||
落羽宗,杀手宗门,擅长暗杀、潜形匿迹与设伏,手段隐秘凌厉,以殡生印等绝技著称,行动不留痕迹。曾拥王牌杀手团队'二十四翎',重视香火情分但亦有叛徒。奉行‘接手无悔’原则,一旦接任务或建立关系便不轻言放弃,高手可大规模集结行动。理念上追求杀中求道,断情绝性,游刃生死,但现任宗主素怀羽更重利益。掌握操控飞禽之术(如告死鸟)用于侦查预警,擅长灵体侦查与阵势配合,作风阴狠诡异而富有策略性,在大战中承担关键穿插任务。与朱勾宗并列为刺客类宗门,以轻功或遁术见长,有跑路之名。参与西联联盟,整体根基虚缈,立场摇摆,缺乏独立主张。,,"水蝶兰, 千机老怪, 素怀羽, 无名杀手, 百鬼道人, 黄, 青, 血, 玄, 素, 玄羽, 洪长老","千里无影, 殡生印, 落羽十杀技, 燃血元息","告死鸟, 搜神冰蚨, 子蚨, 母蚨"
|
||||
回玄宗,当世第一阵法大派,以禁制阵诀与机关术结合见长,禁纹手法传承深厚,布设复杂禁制范围极广,技术独步天下。注重禁制推演与融合,讲究巧思妙用,追求举重若轻、峰回路转的实战效果。同时擅长炼丹制符,材料管控严格,资源珍贵。门风严谨,极重宗门尊严与宝物,对叛徒追杀到底,积极参与正道联合事务,具备强组织力与战术意识。,诸隐山,"玄符真人, 玄化真人","回玄妙手, 峰回路转","宗门宝物(具体名称未提), 断续灵胶, 金击子, 返魂丹, 清心七巧散, 流莹丹, 辟路梭"
|
||||
回玄宗,当世第一阵法大派,以阵法阵诀与机关术结合见长,禁纹手法传承深厚,布设复杂阵法范围极广,技术独步天下。注重阵法推演与融合,讲究巧思妙用,追求举重若轻、峰回路转的实战效果。同时擅长炼丹制符,材料管控严格,资源珍贵。门风严谨,极重宗门尊严与宝物,对叛徒追杀到底,积极参与正道联合事务,具备强组织力与战术意识。,诸隐山,"玄符真人, 玄化真人","回玄妙手, 峰回路转","宗门宝物(具体名称未提), 断续灵胶, 金击子, 返魂丹, 清心七巧散, 流莹丹, 辟路梭"
|
||||
水镜宗,超然中立,以窥探天机、推演气运为修行核心,主持‘水镜之会’发布谶语偈言,权威极高而口风严密。擅长水镜类侦测与传讯之术,注重理性推算与情报分析,行事低调圆滑,善于调停纷争、协调各方,力求自保避祸。不重修为境界,而重缘法能耐,表面清雅出尘,实则世故机变,虽掌握天机却不轻言生死,趋利避凶,影响深远。,位于北齐山中段的水镜洞天,核心为鉴湖,水系如网,灵脉众多,因封禁与地形显得幽静。彻天水镜存放于主河道中枢,是宗门观测天机的核心所在。,"水镜先生, 颜水月, 玉岚道人, 玉岚道姑, 李知客, 李珣, 水月师妹, 天芷上人, 灵喆, 明惑, 伍灵泉, 灵机, 季涯","推演之术, 水镜天心之术, 水镜法, 水镜神术, 镜化, 批命理, 推算劫数, 水镜秘法, 彻天水镜, 水镜之术, 推演天机的妙术, 水华重幕, 水镜大会相关法门, 阵法纹路刻画, 骨络通心之术, 寄魂转生, 无底冥环, 驱尸傀儡术, 血神法门, 截留复现影像之术, 测心映照之术","彻天水镜, 水镜, 扇子(上书‘天机无限,一半一半;信口胡言,且听且看’), 镜傀儡, 墨丝蚶宝, 虹影珠, 流水盘, 水镜偈语"
|
||||
朱勾宗,邪宗大派,通玄界顶尖炼器大宗,以炼器、机关、禁制与暗杀闻名。擅长制造邪门法宝和消耗性武器,手段阴毒狠辣,精于潜匿刺杀、悬红缉赏,行动隐秘且突袭力强。具有杀手组织性质,对叛逆者追杀到底,内部重视核心资源保护,但与宗主关系紧张时易生内乱。,明玉山,位于通玄界中部区域,临近西南丛林。,"百了刀, 明皇戟, 水蝶兰, 遁天刺, 朱勾九杀, 牵魂索, 蚀神刀, 小朱勾, 商侍, 寒玉勾, 疫鬼勾, 戮魂斧, 千机老怪, 邹老哥, 四杀","逆影遁法, 虚昧空遁, 寒玉勾, 刺血法, 暗杀之法, 慑魂魔音, 疫毒, 迭毒法, 专门设计的一套应用法门(用于日轮珠)","小朱勾, 花萼烟魔梭, 缚魂烟萝, 蓝星砂, 灵灭丝, 戮魂斧, 鬼灵珠串, 干天火灵珠, 蚀神刀, 日轮珠"
|
||||
阴阳宗,行事不分正邪,以阴阳双修、媚功与魔功修行为主,擅长摄魂迷心、逆转阴阳、极致变化之道,手段凌厉,杀伐果断,对敌讲究合力围杀与气机操控。宗内体系严密,设日曜书官与月华长史为男女宗主候选人,统御五嫔七卿,等级森严,尊卑有序;师徒关系紧密且具控制性,存在日曜、月华两系权力斗争。注重双修采补、鼎炉玉婴等非常修行手段,涉心魔禁制、精神控制与隐秘布局,行事诡谲深沉,擅长谋略与心理战。虽势力不大,但政治影响力隐现,对外低调中立,倾向自保旁观,必要时主动出击,积威甚重。,具体位置未明,宗主云辇暂驻水镜洞天,与玄海幽明城、千帆城等地有联系,有南返计划。,"阴散人, 秦婉如, 李珣, 云蓝柯, 祈碧, 明玑, 羽侍, 阴重华, 古音, 栖霞, 羽夫人, 婵玉, 水蝶兰, 苏瑜, 吴姬","颠倒阴阳阵法, 阴阳双修之术, 惑神之术, 《阴符经}, 极变阴阳法, 幽脉, 通心法, 入神法, 惑神秘术, 驱魂炼魄通心大法, 不动邪心, 血神煅体, 外化血魇, 血分身, 《血神子}, 天魔舞, 五色神光, 定魂蓝星, 金丸神泥封印术, 碧火流莹咒法, 莲花八密, 摄魂迷心之术, 天罡雷煞之法, 血融之术, 攫灵法, 六御阳阴变","无颜甲, 天冥化阴珠, 定魂蓝星, 金击子, 扫雪铃, 太阴光极幡, 破魂梭, 落魂幡"
|
||||
朱勾宗,邪宗大派,通玄界顶尖炼器大宗,以炼器、机关、阵法与暗杀闻名。擅长制造邪门法宝和消耗性武器,手段阴毒狠辣,精于潜匿刺杀、悬红缉赏,行动隐秘且突袭力强。具有杀手组织性质,对叛逆者追杀到底,内部重视核心资源保护,但与宗主关系紧张时易生内乱。,明玉山,位于通玄界中部区域,临近西南丛林。,"百了刀, 明皇戟, 水蝶兰, 遁天刺, 朱勾九杀, 牵魂索, 蚀神刀, 小朱勾, 商侍, 寒玉勾, 疫鬼勾, 戮魂斧, 千机老怪, 邹老哥, 四杀","逆影遁法, 虚昧空遁, 寒玉勾, 刺血法, 暗杀之法, 慑魂魔音, 疫毒, 迭毒法, 专门设计的一套应用法门(用于日轮珠)","小朱勾, 花萼烟魔梭, 缚魂烟萝, 蓝星砂, 灵灭丝, 戮魂斧, 鬼灵珠串, 干天火灵珠, 蚀神刀, 日轮珠"
|
||||
阴阳宗,行事不分正邪,以阴阳双修、媚功与魔功修行为主,擅长摄魂迷心、逆转阴阳、极致变化之道,手段凌厉,杀伐果断,对敌讲究合力围杀与气机操控。宗内体系严密,设日曜书官与月华长史为男女宗主候选人,统御五嫔七卿,等级森严,尊卑有序;师徒关系紧密且具控制性,存在日曜、月华两系权力斗争。注重双修采补、鼎炉玉婴等非常修行手段,涉心魔阵法、精神控制与隐秘布局,行事诡谲深沉,擅长谋略与心理战。虽势力不大,但政治影响力隐现,对外低调中立,倾向自保旁观,必要时主动出击,积威甚重。,具体位置未明,宗主云辇暂驻水镜洞天,与玄海幽明城、千帆城等地有联系,有南返计划。,"阴散人, 秦婉如, 李珣, 云蓝柯, 祈碧, 明玑, 羽侍, 阴重华, 古音, 栖霞, 羽夫人, 婵玉, 水蝶兰, 苏瑜, 吴姬","颠倒阴阳阵法, 阴阳双修之术, 惑神之术, 《阴符经}, 极变阴阳法, 幽脉, 通心法, 入神法, 惑神秘术, 驱魂炼魄通心大法, 不动邪心, 血神煅体, 外化血魇, 血分身, 《血神子}, 天魔舞, 五色神光, 定魂蓝星, 金丸神泥封印术, 碧火流莹咒法, 莲花八密, 摄魂迷心之术, 天罡雷煞之法, 血融之术, 攫灵法, 六御阳阴变","无颜甲, 天冥化阴珠, 定魂蓝星, 金击子, 扫雪铃, 太阴光极幡, 破魂梭, 落魂幡"
|
||||
一斗米教,行事诡秘,介于正邪之间,被视作异类,龙蛇混杂,接纳三教九流与散修,势力较弱,以维持道统为要。擅长幻术,精于伪装潜入,可参与西联联盟活动。依赖人间香火供奉获取念力修炼,与散修盟会冲突较小,总体保守自保,在局势变动中谋求自身利益。,人间界,"公孙老哥, 泌阳子, 重华子, 孟章神君, 离天妖道","吸取信徒虔诚供奉所形成的念力精进修为, 采阴补阳的法门, 白莲化生",
|
||||
星玑剑宗,桀骜不驯,强势霸道,护短重亲疏,杀伐果决,重视宗门信物与阵法控制;精通天星推演与阵法禁制,行事严谨封闭,对外警惕,注重清誉与独立性;受天垣翁主导,作风强硬,但因重大变故后宗主仙去、高手陨落,现趋于保守避世,封闭星河千载,不与外界往来。,位于星河(六大绝地之一,位置飘忽),中枢在太微垣聚星台,依托周天星力布设禁制,为核心所在。,"天垣老儿, 允星, 毕宿, 天垣翁, 王罗, 明玑, 天垣道友","化生星典, 星玑剑宗独门法诀(可吸纳炼化星力), 《化星秘典》, 星变图, 破军仙剑剑诀, 星斗入剑, 剑化天星, 调动方圆十里禁制, 八阵图, 天心灵犀之术","参星盘, 定星, 黑曜晶, 破军仙剑, 化星剑帖, 九天星剑"
|
||||
不言宗,奉行‘大巧不言’之道,精于阵法,擅长布设无声无息的禁制与突发性攻击,注重阵法与自然融合,风格内敛深奥,偏向水火交融、地脉为基的生克之法。作为阵法门派之一,与回玄宗、明心剑宗并列,曾掌控雾隐轩,留下深刻印记。宗风低调隐秘,不轻易显露手段,性好游历,前任宗主屈拙语曾遍游六大绝地。势力较弱,对结盟持保留态度,只求维持道统,尚未表态立场。,,"屈拙语, 乌吉","默语篇, 大巧不言, 弹指惊雷",
|
||||
不夜城,正道九宗魁首之一,以防御见长,设有万里极光壁与严密禁制,能发动大型阵法‘永夜极光’抵御外敌。组织有序,有中枢指挥系统,曾统御一方并主持大局,虽因散修盟会压力被迫内迁、放弃祖地,但仍坚韧图强,志在复兴。宗主天芷上人性格锋芒毕露、言辞讥诮,行事看似随性实则深谋远虑,可为振兴宗门不惜入魔,具备极端手段与理智并存的特质。宗门重视辈分秩序、先师遗物与传统,内部可有限质疑宗主,但受尊卑约束。精通幻术,善用隐忍算计之策,行欲取先予、虚实结合、连环设局,为复仇可不惜代价。遭遇袭击后反应强硬,如许阁老被害引发高层震动。,原位于北海之滨,极地圈内,临近夜摩天,为正道十宗之一,曾设驻守监视夜摩天变化;后因形势所迫举宗内迁。,"天芷上人, 玉岚道人, 颜水月, 天河, 季涯, 许阁老, 极影真人, 天芷, 天河长老","极光玄真法, 永夜极光, 极光千变法, 极光千变, 极光元磁, 五色神光, 心魔精进法, 御剑之术, 极光玄法, 血神子, 先天五色神光, 回玄阵法","天仪盘, 虹影珠, 永夜极光, 万里极光壁, 宗门神器, 造化金丹, 锁心寒铁"
|
||||
星玑剑宗,桀骜不驯,强势霸道,护短重亲疏,杀伐果决,重视宗门信物与阵法控制;精通天星推演与阵法阵法,行事严谨封闭,对外警惕,注重清誉与独立性;受天垣翁主导,作风强硬,但因重大变故后宗主仙去、高手陨落,现趋于保守避世,封闭星河千载,不与外界往来。,位于星河(六大绝地之一,位置飘忽),中枢在太微垣聚星台,依托周天星力布设阵法,为核心所在。,"天垣老儿, 允星, 毕宿, 天垣翁, 王罗, 明玑, 天垣道友","化生星典, 星玑剑宗独门法诀(可吸纳炼化星力), 《化星秘典》, 星变图, 破军仙剑剑诀, 星斗入剑, 剑化天星, 调动方圆十里阵法, 八阵图, 天心灵犀之术","参星盘, 定星, 黑曜晶, 破军仙剑, 化星剑帖, 九天星剑"
|
||||
不言宗,奉行‘大巧不言’之道,精于阵法,擅长布设无声无息的阵法与突发性攻击,注重阵法与自然融合,风格内敛深奥,偏向水火交融、地脉为基的生克之法。作为阵法门派之一,与回玄宗、明心剑宗并列,曾掌控雾隐轩,留下深刻印记。宗风低调隐秘,不轻易显露手段,性好游历,前任宗主屈拙语曾遍游六大绝地。势力较弱,对结盟持保留态度,只求维持道统,尚未表态立场。,,"屈拙语, 乌吉","默语篇, 大巧不言, 弹指惊雷",
|
||||
不夜城,正道九宗魁首之一,以防御见长,设有万里极光壁与严密阵法,能发动大型阵法‘永夜极光’抵御外敌。组织有序,有中枢指挥系统,曾统御一方并主持大局,虽因散修盟会压力被迫内迁、放弃祖地,但仍坚韧图强,志在复兴。宗主天芷上人性格锋芒毕露、言辞讥诮,行事看似随性实则深谋远虑,可为振兴宗门不惜入魔,具备极端手段与理智并存的特质。宗门重视辈分秩序、先师遗物与传统,内部可有限质疑宗主,但受尊卑约束。精通幻术,善用隐忍算计之策,行欲取先予、虚实结合、连环设局,为复仇可不惜代价。遭遇袭击后反应强硬,如许阁老被害引发高层震动。,原位于北海之滨,极地圈内,临近夜摩天,为正道十宗之一,曾设驻守监视夜摩天变化;后因形势所迫举宗内迁。,"天芷上人, 玉岚道人, 颜水月, 天河, 季涯, 许阁老, 极影真人, 天芷, 天河长老","极光玄真法, 永夜极光, 极光千变法, 极光千变, 极光元磁, 五色神光, 心魔精进法, 御剑之术, 极光玄法, 血神子, 先天五色神光, 回玄阵法","天仪盘, 虹影珠, 永夜极光, 万里极光壁, 宗门神器, 造化金丹, 锁心寒铁"
|
||||
噬魔宗,邪道第一大宗,势力强盛,被誉为‘当之无愧的第一邪宗’,属通玄第一魔宗。行事诡谲霸道,阴狠残忍,擅长搜精噬血、操控怨念与魂魄,修炼阴毒魔功,以夺魄化形为无上秘法。作风张扬又隐秘,布局深远,情报网络发达,惯于借势谋利,派出暗探监视目标。宗主罗摩什性喜饮血,豪情万丈,强者为尊,为西联联盟魁首之一,亦是北盟潜在打击目标。,陷空山,"罗老妖, 飞天猿魔, 罗摩什, 雷喙鹰, 摩什上师, 不成器的弟子","天魔魅影, 搜精噬血, 飞魃讯法, 夺魄三化",
|
||||
天妖宗,邪宗之一,霸道强势,以力破局,行事张扬,讲究因果报应,乐见妙化宗动作但未有实质举动。,,天妖凤凰,"控火之术, 离化神光, 血劫烛元神光",青碧玉羽
|
||||
毒隐宗,邪宗之一,手段狠辣阴损,擅长用剧毒无差别杀伤并精准控制毒性范围,以制毒炼丹闻名天下,技术独步此界。与朱勾宗交换法门,能炼制如‘赤雪乱’等强效毒素,炼毒布陷之能天下无双。领袖狡诈如老狐狸,善于权谋,乐见他宗争斗而按兵不动,属西联联盟核心成员。,鸠盘山,"腐骨童子, 褚辰",,
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
@@ -228,7 +228,7 @@ if __name__ == "__main__":
|
||||
]
|
||||
sect_prompt_base = "像素化的仙侠宗门场景图片,极度像素化,颗粒感强,线条轮廓粗,极简主义,二次元风格漫画图片。"
|
||||
sect_affixes = [
|
||||
# "山巅飘渺云海,云纹禁制光芒环绕,远处群峰。",
|
||||
# "山巅飘渺云海,云纹阵法光芒环绕,远处群峰。",
|
||||
# "灵兽栖地,兽栏密布,岩石兽穴。",
|
||||
# "湖面倒影,中央悬浮巨大水镜,镜面波光粼粼,雾气弥漫。",
|
||||
# "幽冥宗门,阴暗昏沉,黑雾弥漫,冷厉气息,幽蓝鬼火点点。",
|
||||
@@ -238,7 +238,7 @@ if __name__ == "__main__":
|
||||
# "幽影之地,暗影重重,光影交错,幽冥之气,黑雾吞噬轮廓。",
|
||||
# "船帆如云,炼器炉火。",
|
||||
"雅致园林,丝竹管弦,百花盛开,隐约音律符文,春意盎然。", # 妙化宗
|
||||
"云雾缭绕山峰,无数禁制光阵层叠,晦暗不明,神秘莫测。", # 回玄宗
|
||||
"云雾缭绕山峰,无数阵法光阵层叠,晦暗不明,神秘莫测。", # 回玄宗
|
||||
"极光绚丽,万年寒冰城墙,流光溢彩,如梦似幻,不夜之城。", # 不夜城
|
||||
"雄奇山峰,紫气东来,浩然正气光柱冲天,书声琅琅幻象。", # 天行健宗
|
||||
"险恶山脉,血雾弥漫,怪石嶙峋,白骨累累,狂野血腥。", # 噬魔宗
|
||||
|
||||
Reference in New Issue
Block a user