diff --git a/src/classes/sect.py b/src/classes/sect.py index 77ba048..9ad312b 100644 --- a/src/classes/sect.py +++ b/src/classes/sect.py @@ -6,7 +6,13 @@ from src.utils.df import game_configs from src.utils.config import CONFIG -# 宗门驻地 +""" +宗门、宗门总部基础数据。 +驻地名称与描述已迁移到 sect_region.csv,供地图区域系统使用。 +此处仅保留宗门本体信息与头像编辑所需的静态字段。 +""" + +# 宗门驻地(基础展示数据,具体地图位置在 sect_region.csv 中定义) @dataclass class SectHeadQuarter: """ @@ -61,9 +67,10 @@ def _load_sects() -> tuple[dict[int, Sect], dict[str, Sect]]: sect_surnames=_split_names(row["sect_surnames"]), male_sect_given_names=male_given_names, female_sect_given_names=female_given_names, + # 保留旧字段的兼容读取(如旧csv仍包含headquarter_*列则读入;否则使用宗门名与空描述) headquarter=SectHeadQuarter( - name=(str(row["headquarter_name"]) if str(row["headquarter_name"]).strip() else str(row["name"])), - desc=str(row["headquarter_desc"]), + name=(str(row.get("headquarter_name", "")).strip() or str(row["name"])) , + desc=str(row.get("headquarter_desc", "")), image=image_path, ), ) diff --git a/src/classes/sect_region.py b/src/classes/sect_region.py new file mode 100644 index 0000000..bcafa55 --- /dev/null +++ b/src/classes/sect_region.py @@ -0,0 +1,20 @@ +from dataclasses import dataclass +from pathlib import Path + +from src.classes.region import Region + + +@dataclass +class SectRegion(Region): + """ + 宗门总部区域:仅用于显示宗门总部的名称与描述。 + 无额外操作或属性。 + """ + image_path: str | None = None + + def get_region_type(self) -> str: + return "sect" + + # hover 信息沿用基类,仅显示名称与描述 + + diff --git a/src/front/app.py b/src/front/app.py index 7dfea84..eb37bb9 100644 --- a/src/front/app.py +++ b/src/front/app.py @@ -7,7 +7,7 @@ from src.classes.avatar import Avatar, Gender from .theme import COLORS from .fonts import create_font, get_region_font as _get_region_font_cached -from .assets import load_tile_images, load_avatar_images +from .assets import load_tile_images, load_avatar_images, load_sect_images from .rendering import ( draw_map, draw_region_labels, @@ -64,6 +64,7 @@ class Front: self.colors = COLORS self.tile_images = load_tile_images(self.pygame, self.tile_size) + self.sect_images = load_sect_images(self.pygame, self.tile_size) self.male_avatars, self.female_avatars = load_avatar_images(self.pygame, self.tile_size) self.avatar_images: Dict[str, object] = {} self._assign_avatar_images() @@ -131,6 +132,9 @@ class Front: self.margin, STATUS_BAR_HEIGHT, ) + # 底图后叠加宗门总部图层(2x2) + from .rendering import draw_sect_headquarters + draw_sect_headquarters(pygame, self.screen, self.world, self.sect_images, self.tile_size, self.margin, STATUS_BAR_HEIGHT) hovered_region = draw_region_labels( pygame, self.screen, diff --git a/src/front/assets.py b/src/front/assets.py index 1792bec..f9d681f 100644 --- a/src/front/assets.py +++ b/src/front/assets.py @@ -1,5 +1,6 @@ import os from typing import Dict, List +from pathlib import Path from src.classes.tile import TileType @@ -50,6 +51,25 @@ def load_avatar_images(pygame_mod, tile_size: int): return male_avatars, female_avatars -__all__ = ["load_tile_images", "load_avatar_images"] +def load_sect_images(pygame_mod, tile_size: int): + """ + 加载宗门总部图片,缩放为 2x2 tile 大小,返回按文件名(不含后缀)为键的图像字典。 + 文件名建议与宗门名称一致。 + """ + images: Dict[str, object] = {} + base_dir = Path("assets/sects") + if base_dir.exists(): + for filename in base_dir.iterdir(): + if filename.suffix.lower() == ".png" and filename.name != "original.png": + try: + image = pygame_mod.image.load(str(filename)) + scaled = pygame_mod.transform.scale(image, (tile_size * 2, tile_size * 2)) + images[filename.stem] = scaled + except pygame_mod.error: + continue + return images + + +__all__ = ["load_tile_images", "load_avatar_images", "load_sect_images"] diff --git a/src/front/rendering.py b/src/front/rendering.py index ec4ce09..94b4917 100644 --- a/src/front/rendering.py +++ b/src/front/rendering.py @@ -38,6 +38,34 @@ def draw_map(pygame_mod, screen, colors, world, tile_images, ts: int, m: int, to draw_grid(pygame_mod, screen, colors, map_obj, ts, m, top_offset) +def draw_sect_headquarters(pygame_mod, screen, world, sect_images: dict, ts: int, m: int, top_offset: int = 0): + """ + 在底图绘制完成后叠加绘制宗门总部(2x2 tile)。 + 以区域左上角(north_west_cor)为锚点绘制。 + """ + for region in world.map.regions.values(): + if getattr(region, "get_region_type", lambda: "")() != "sect": + continue + img_path: str | None = getattr(region, "image_path", None) + if not img_path: + # 可回退到按名称找图:期望 assets/sects/{region.name}.png + key = str(getattr(region, "name", "")) + image = sect_images.get(key) + else: + key = str(pygame_mod.Path(img_path).stem) if hasattr(pygame_mod, "Path") else img_path.split("/")[-1].split("\\")[-1].split(".")[0] + image = sect_images.get(key) + if not image: + # 未加载到图片则跳过 + continue + try: + nw = tuple(map(int, str(getattr(region, "north_west_cor", "0,0")).split(","))) + except Exception: + continue + x_px = m + nw[0] * ts + y_px = m + top_offset + nw[1] * ts + screen.blit(image, (x_px, y_px)) + + def calculate_font_size_by_area(tile_size: int, area: int) -> int: base = int(tile_size * 1.1) growth = int(max(0, min(24, (area ** 0.5)))) @@ -48,11 +76,10 @@ def draw_region_labels(pygame_mod, screen, colors, world, get_region_font, tile_ ts = tile_size m = margin mouse_x, mouse_y = pygame_mod.mouse.get_pos() - from src.classes.region import regions_by_id hovered_region = None # 以区域面积降序放置,优先保证大区域标签可读性 - regions = sorted(list(regions_by_id.values()), key=lambda r: getattr(r, "area", 0), reverse=True) + regions = sorted(list(world.map.regions.values()), key=lambda r: getattr(r, "area", 0), reverse=True) placed_rects = [] # 已放置标签的矩形列表,用于碰撞检测 diff --git a/src/run/create_map.py b/src/run/create_map.py index 83a66c2..3d06281 100644 --- a/src/run/create_map.py +++ b/src/run/create_map.py @@ -1,6 +1,9 @@ from src.classes.map import Map from src.classes.tile import TileType from src.classes.essence import Essence, EssenceType +from src.classes.sect_region import SectRegion +from src.classes.region import Shape +from src.classes.sect import Sect def create_cultivation_world_map() -> Map: """ @@ -20,6 +23,49 @@ def create_cultivation_world_map() -> Map: return game_map +def add_sect_headquarters(game_map: Map, enabled_sects: list[Sect]): + """ + 根据已启用的宗门列表,为其添加总部区域(2x2或1x2等小矩形,hover仅显示名称与描述)。 + 若未启用(列表中无该宗门),则不添加对应总部。 + """ + # 为九个宗门设计坐标(根据地图地形大势和叙事): + # 仅登记矩形区域的西北角与东南角 + locs: dict[str, tuple[tuple[int, int], tuple[int, int]]] = { + "明心剑宗": ((36, 10), (37, 11)), # 北部山脉以南的名门仙山 + "百兽宗": ((22, 22), (23, 23)), # 中西部靠近山林 + "水镜宗": ((58, 22), (59, 23)), # 湖心三岛——近东海内陆湖 + "冥王宗": ((66, 8), (67, 9)), # 东北近海的群岛 + "朱勾宗": ((48, 8), (49, 9)), # 东北内陆山地近雪域 + "合欢宗": ((62, 40), (63, 41)), # 东南近海桃花岛 + "镇魂宗": ((30, 46), (31, 47)), # 极南海上礁岛 + "幽魂噬影宗":((44, 38), (45, 39)), # 南部雨林深处 + "千帆城": ((60, 28), (61, 29)), # 海上浮岛靠近入海口 + } + + name_to_sect = {s.name: s for s in enabled_sects} + + for sect_name, (nw, se) in locs.items(): + sect = name_to_sect.get(sect_name) + if sect is None: + continue + # 名称与描述来自 sect.headquarter;若为空则用 sect 名称/描述 + hq_name = getattr(sect.headquarter, "name", sect.name) or sect.name + hq_desc = getattr(sect.headquarter, "desc", sect.desc) or sect.desc + region = SectRegion( + id=400 + sect.id, # 4xx 预留给宗门总部区域id + name=hq_name, + desc=hq_desc, + shape=Shape.RECTANGLE, + north_west_cor=f"{nw[0]},{nw[1]}", + south_east_cor=f"{se[0]},{se[1]}", + image_path=str(getattr(sect.headquarter, "image", None)), + ) + game_map.regions[region.id] = region + game_map.region_names[region.name] = region + + # 添加完成后,重新分配到 tiles + _assign_regions_to_tiles(game_map) + def _create_base_terrain(game_map: Map): """创建基础地形""" width, height = game_map.width, game_map.height diff --git a/src/run/run.py b/src/run/run.py index 42854c7..0ba828e 100644 --- a/src/run/run.py +++ b/src/run/run.py @@ -18,7 +18,7 @@ from src.classes.calendar import Month, Year, MonthStamp, create_month_stamp from src.classes.cultivation import CultivationProgress from src.classes.root import Root from src.classes.age import Age -from src.run.create_map import create_cultivation_world_map +from src.run.create_map import create_cultivation_world_map, add_sect_headquarters from src.utils.names import get_random_name, get_random_name_for_sect from src.utils.id_generator import get_avatar_id from src.utils.config import CONFIG @@ -58,6 +58,9 @@ def make_avatars(world: World, count: int = 12, current_month_stamp: MonthStamp enabled_sects = list(sects_by_id.values()) random.shuffle(enabled_sects) enabled_sects = enabled_sects[:max_sects] if use_sects else [] + # 在地图上添加启用宗门的总部(仅显示名称与描述) + if enabled_sects: + add_sect_headquarters(world.map, enabled_sects) # 循环均匀分配宗门成员(轮询宗门) sect_assign_index = 0 sect_member_count = 0 diff --git a/static/game_configs/sect.csv b/static/game_configs/sect.csv index 9668a94..77ea81c 100644 --- a/static/game_configs/sect.csv +++ b/static/game_configs/sect.csv @@ -1,11 +1,11 @@ -id,name,desc,headquarter_name,headquarter_desc,member_act_style,alignment,sect_surnames,male_sect_given_names,female_sect_given_names -,,宗门名称与描述,驻地名称,驻地描述,宗门成员行事风格,阵营(正/中/邪),宗门常用姓氏(分号分隔),男性常用名(分号分隔),女性常用名(分号分隔) -1,明心剑宗,通玄界东方第一宗,以无上剑道称雄于世。云纹禁制为不传心法。,连霞山,连霞山坐忘峰下,是名门仙山的主峰。山上设有弟子修炼之地,环境清幽。,清明克己,行止如一。重剑与心法并重,讲究明心见性。,正,明;灵;清,阁;松;德;吉;明和;澜;彦;珣;智;海;灵泉,如;玑;碧;清霁;素心;明珑;玄音;澄如;玉衡 -2,百兽宗,以驯养灵兽闻名,豢养各种妖兽灵怪为战力。,玄灵洞,玄灵洞位于十万大山深处,洞府依托一座千丈高的灵山开凿而成,洞口宽达百丈,形似猛兽张口。洞内纵横交错,共有九十九层洞天,每层都驯养着不同品阶的灵兽妖兽。,你是百兽宗弟子。你言语直接,重视力量与血性,崇尚狩猎与搏斗。,邪,,驼王;飞熊;虎魄;狼行;熊罡;白猿;石坚;山岚;青鬃;玄爪,狐绮;白貂;青翎;雪牙;赤羽;玄狸;灵爪;月狐 -3,水镜宗,正道十宗之一,实则严守中立。拥有仙界异宝"彻天水镜"可预知未来。,碧波湖,水镜宗建于碧波湖心的三座仙岛之上,湖水清澈如镜,终年波澜不兴。三岛之间以水晶长桥相连,宫殿楼阁皆为水晶琉璃所筑,通体透明,倒映湖中,虚实难辨。,你是水镜宗弟子。你处事冷静圆融,喜以柔克刚,擅借力与反制。,中,水;镜;颜;玉;寒;霜;冰;清;沐;阮,岚;照心;寒江,水月;映月;寒影;秋水;轻漪;雪落;如镜;青荷;凝霜 -4,冥王宗,行走幽冥之道,术法阴冷狠厉。,七鬼角,冥王宗位于七鬼角群岛上,宗门四面临海,周围暗礁密布,巨浪狂潮起落之间,在暗礁周围生成无数令人望而生畏的暗流漩涡。群岛周围千万年来投入了多少凶魂厉鬼,海浪起啸之时,万鬼齐哭,遮天蔽日。,你是冥王宗弟子。你言辞冷厉少情,敬畏因果而不惧杀伐,偏向效率与结果。,邪,宋;元;冥;王;玄;幽;夜;白;江;冷,元敕;元难;元烁;冥焰;噬魂;夜阙;幽垣;玄骨;寒魄;冥狱;影灭;夜行,冥霜;幽绫;夜珑;寒鸢;阎铃;魇瑶;玄魄;幽棂 -5,朱勾宗,邪宗大派。以炼器、机关、暗杀闻名于世,素来阴毒冷僻。,明玉山,明玉山通体由罕见的明玉石构成,山体呈现出诡异的青白色泽,在月光下更是泛着幽冷的光芒。山中宫殿楼阁皆为玉石所筑,看似华丽却处处暗藏杀机。殿宇之间机关重重,暗道密布。,你是朱勾宗弟子。你直面欲望与代价,不惧黑暗,以攻伐见长。,邪,朱;勾;血;狱;百;,血手;勾魂;朱砂;赤狱;凝血;摄魄;夺心;吞灵;渊渟;夜烬,朱绫;夜鸢;绯刃;寒簪;明玥;凝芒;血莹;玉珥 -6,合欢宗,以情入道,双修与魅术并重,善驭人心,长于权变。,桃花岛,合欢宗坐落于东海桃花岛上,岛上四季桃花盛开,永不凋零,花瓣随风飘舞,铺满整座仙岛。宗门建筑以粉红色调为主,雕梁画栋,极尽奢华。殿宇楼阁之间云雾缭绕,隐约可见成双成对的弟子在其间修炼。,你是合欢宗弟子。你辞令婉转,善于拿捏人欲与局势,以柔制刚。,中,合;欢;苏;陆;柳;花;月;楚;顾;白,流烟,婉心;轻柔;疏影;如梦;绮念;月华;惜香;慕雪;倾城 -7,镇魂宗,铁血风格,擅安魂、封邪、渡厄,兼有刚烈镇压之术。,落魂海,位于极南海上。镇魂海常年有妖兽作乱,海域凶险。宗门建筑立于海中礁岛之上,以镇魂钟为中心,钟声可震慑方圆千里之内的妖魂。,你是镇魂宗弟子。你肃穆沉稳,重安魂镇邪,少言而果决。,正,厉;卢;镇;魂;钟;青;凌;白;楚;顾,斗量;阳;镇灵;定魄;钟离;安魂;肃霜;白岭;清钟;涤秽;正鸣;宁川,清宁;素铃;靖霜;澄心;灵钟;镇月;安祈;涤魂 -8,幽魂噬影宗,镇宗典籍《幽冥录》。幽明气为根基。,鬼门湖,鬼门湖位于原始森林深处,重重大山围拢的平原地带。参天巨木、缠绕藤蔓、终日浮游不散的瘴气,还有因宗门秘法而生就的层层迷雾,将这里与外界完全隔离,透不进一点光来。,你是幽魂噬影宗弟子。你行事隐秘果断,重结果轻虚名,擅潜行与出其不意。,邪,冥;阎;鬼;百;幽;归;应;阴;碧;夜,璃;无藏;馑;噬影;隐魄;夜藏;无相;玄影;摄魂;遁形;寒星;绝响;空痕,采儿;幽姝;冥绮;寒灯;影绫;夜绡;魇歌;暗萝 -9,千帆城,炼器大宗,巧匠云集。著名法宝有灵灭丝、定魂蓝星、天罗网、万里极光壁、飞翼等。商旅云集,自成体系。,天星海,千帆城建于天星海中央的巨型浮岛之上,整座城池由无数法器拼接而成,城外海面上停泊着数以千计的法器灵舟,帆樯如林,蔚为壮观。城中高塔林立,每座塔顶都有炼器炉火日夜不息,烟柱冲天。,你是千帆城修士。你务实精明,重交易与信誉,崇尚规则与秩序。,中,商;楚;顾;白;苏;林;叶;秦;赵;魏,商行;持衡;清评;问价;立契;通衡;问道;理市;衡准;守约,素蓝;明衡;巧心;青帆;绫舟;观星;衡绫;星槎 +id,name,desc,member_act_style,alignment,sect_surnames,male_sect_given_names,female_sect_given_names +,,宗门名称与描述,宗门成员行事风格,阵营(正/中/邪),宗门常用姓氏(分号分隔),男性常用名(分号分隔),女性常用名(分号分隔) +1,明心剑宗,通玄界东方第一宗,以无上剑道称雄于世。云纹禁制为不传心法。,清明克己,行止如一。重剑与心法并重,讲究明心见性。,正,明;灵;清,阁;松;德;吉;明和;澜;彦;珣;智;海;灵泉,如;玑;碧;清霁;素心;明珑;玄音;澄如;玉衡 +2,百兽宗,以驯养灵兽闻名,豢养各种妖兽灵怪为战力。,你是百兽宗弟子。你言语直接,重视力量与血性,崇尚狩猎与搏斗。,邪,,驼王;飞熊;虎魄;狼行;熊罡;白猿;石坚;山岚;青鬃;玄爪,狐绮;白貂;青翎;雪牙;赤羽;玄狸;灵爪;月狐 +3,水镜宗,正道十宗之一,实则严守中立。拥有仙界异宝"彻天水镜"可预知未来。,你是水镜宗弟子。你处事冷静圆融,喜以柔克刚,擅借力与反制。,中,水;镜;颜;玉;寒;霜;冰;清;沐;阮,岚;照心;寒江,水月;映月;寒影;秋水;轻漪;雪落;如镜;青荷;凝霜 +4,冥王宗,行走幽冥之道,术法阴冷狠厉。,你是冥王宗弟子。你言辞冷厉少情,敬畏因果而不惧杀伐,偏向效率与结果。,邪,宋;元;冥;王;玄;幽;夜;白;江;冷,元敕;元难;元烁;冥焰;噬魂;夜阙;幽垣;玄骨;寒魄;冥狱;影灭;夜行,冥霜;幽绫;夜珑;寒鸢;阎铃;魇瑶;玄魄;幽棂 +5,朱勾宗,邪宗大派。以炼器、机关、暗杀闻名于世,素来阴毒冷僻。,你是朱勾宗弟子。你直面欲望与代价,不惧黑暗,以攻伐见长。,邪,朱;勾;血;狱;百;,血手;勾魂;朱砂;赤狱;凝血;摄魄;夺心;吞灵;渊渟;夜烬,朱绫;夜鸢;绯刃;寒簪;明玥;凝芒;血莹;玉珥 +6,合欢宗,以情入道,双修与魅术并重,善驭人心,长于权变。,你是合欢宗弟子。你辞令婉转,善于拿捏人欲与局势,以柔制刚。,中,合;欢;苏;陆;柳;花;月;楚;顾;白,流烟,婉心;轻柔;疏影;如梦;绮念;月华;惜香;慕雪;倾城 +7,镇魂宗,铁血风格,擅安魂、封邪、渡厄,兼有刚烈镇压之术。,你是镇魂宗弟子。你肃穆沉稳,重安魂镇邪,少言而果决。,正,厉;卢;镇;魂;钟;青;凌;白;楚;顾,斗量;阳;镇灵;定魄;钟离;安魂;肃霜;白岭;清钟;涤秽;正鸣;宁川,清宁;素铃;靖霜;澄心;灵钟;镇月;安祈;涤魂 +8,幽魂噬影宗,镇宗典籍《幽冥录》。幽明气为根基。,你是幽魂噬影宗弟子。你行事隐秘果断,重结果轻虚名,擅潜行与出其不意。,邪,冥;阎;鬼;百;幽;归;应;阴;碧;夜,璃;无藏;馑;噬影;隐魄;夜藏;无相;玄影;摄魂;遁形;寒星;绝响;空痕,采儿;幽姝;冥绮;寒灯;影绫;夜绡;魇歌;暗萝 +9,千帆城,炼器大宗,巧匠云集。著名法宝有灵灭丝、定魂蓝星、天罗网、万里极光壁、飞翼等。商旅云集,自成体系。,你是千帆城修士。你务实精明,重交易与信誉,崇尚规则与秩序。,中,商;楚;顾;白;苏;林;叶;秦;赵;魏,商行;持衡;清评;问价;立契;通衡;问道;理市;衡准;守约,素蓝;明衡;巧心;青帆;绫舟;观星;衡绫;星槎 diff --git a/static/game_configs/sect_region.csv b/static/game_configs/sect_region.csv new file mode 100644 index 0000000..c836cf0 --- /dev/null +++ b/static/game_configs/sect_region.csv @@ -0,0 +1,12 @@ +sect_id,headquarter_name,headquarter_desc +"与 sect.csv 的 id 对应","宗门驻地名称","宗门驻地描述" +1,连霞山,连霞山坐忘峰下,是名门仙山的主峰。山上设有弟子修炼之地,环境清幽。 +2,玄灵洞,玄灵洞位于十万大山深处,洞府依托一座千丈高的灵山开凿而成,洞口宽达百丈,形似猛兽张口。洞内纵横交错,共有九十九层洞天,每层都驯养着不同品阶的灵兽妖兽。 +3,碧波湖,水镜宗建于碧波湖心的三座仙岛之上,湖水清澈如镜,终年波澜不兴。三岛之间以水晶长桥相连,宫殿楼阁皆为水晶琉璃所筑,通体透明,倒映湖中,虚实难辨。 +4,七鬼角,冥王宗位于七鬼角群岛上,宗门四面临海,周围暗礁密布,巨浪狂潮起落之间,在暗礁周围生成无数令人望而生畏的暗流漩涡。群岛周围千万年来投入了多少凶魂厉鬼,海浪起啸之时,万鬼齐哭,遮天蔽日。 +5,明玉山,明玉山通体由罕见的明玉石构成,山体呈现出诡异的青白色泽,在月光下更是泛着幽冷的光芒。山中宫殿楼阁皆为玉石所筑,看似华丽却处处暗藏杀机。殿宇之间机关重重,暗道密布。 +6,桃花岛,合欢宗坐落于东海桃花岛上,岛上四季桃花盛开,永不凋零,花瓣随风飘舞,铺满整座仙岛。宗门建筑以粉红色调为主,雕梁画栋,极尽奢华。殿宇楼阁之间云雾缭绕,隐约可见成双成对的弟子在其间修炼。 +7,落魂海,位于极南海上。镇魂海常年有妖兽作乱,海域凶险。宗门建筑立于海中礁岛之上,以镇魂钟为中心,钟声可震慑方圆千里之内的妖魂。 +8,鬼门湖,鬼门湖位于原始森林深处,重重大山围拢的平原地带。参天巨木、缠绕藤蔓、终日浮游不散的瘴气,还有因宗门秘法而生就的层层迷雾,将这里与外界完全隔离,透不进一点光来。 +9,天星海,千帆城建于天星海中央的巨型浮岛之上,整座城池由无数法器拼接而成,城外海面上停泊着数以千计的法器灵舟,帆樯如林,蔚为壮观。城中高塔林立,每座塔顶都有炼器炉火日夜不息,烟柱冲天。 +