模组:地图
← 目录
此页面解释如何编辑地图。这是面向模组开发者的高级指南。
简介
基本概念
- 地图是指特定区域地形(水、悬崖、陆地等)、地形特征(灌木等)、建筑、道路、触发器等的布局。当您到达某一区域的边界或进入建筑中,屏幕变黑从而转场时,您也就切换了地图。
- 每个地图都有层层重叠的图层。靠前的层中的物体会遮住靠后层中的物体。标准情况下,各层从后到前如下:
层名 典型内容 Back(后层) 地形、水体和基本特征(例如永久性道路)。 Buildings(建筑层) 用于放置建筑(如农舍)。任何置于此层的地块将像一堵墙般不可穿过,除非指定了地块属性"Passable" "T"。 Paths(道路层) 地板、道路、草、碎片(例如“道路”地块表中的石头、杂草、树桩),此类玩家可移除的物品。 Front(前层) 画在其他物体前的物体,例如树。当玩家在这类物品北方时,则画在玩家贴图前方;若在南方,则画在玩家贴图后方。 AlwaysFront(置顶层) 总是画在最顶层的物品,例如玩家贴图。一个典型用途是绘制落叶等前景效果。 - 可以通过在原版层名后面添加偏移量的方法来添加任意数量的新层。原版层名即Back、Buildings、Front 或 AlwaysFront。 例如,Back-1层会置于Back底层,而Back2则会被置于Back顶层。可以更改偏移量以创建更多层。 此写法仅对层渲染有用;地块属性和碰撞都必须写在原版的、无偏移的图层中。
- (使用Tiled)在Tiled中,这五种图层中的每个又细分为两种图层,即 Objects Layer(粉色云状图标)和 Tile Layer(蓝色网格图标)。Tile Layer用于编辑地图(放置/移除地块),Objects Layer用于添加和编辑地块数据。自定义图层必须符合上述命名规范。注意有的地图没有Paths层和AlwaysFront层。
- 每层都由许多地块组成,所谓地块就是排布在网格中的16×16像素方块,用于显示地图。每个地块都可以拥有属性(例如可否通过),特殊逻辑(例如玩家踩上触发动作),以及要显示的贴图。贴图应当表示为贴图索引(或地块索引),也就是在贴图在它的贴图集中的位置(见下文)。
- 每个地图都有一至多个贴图集(当谈论模组时,也称作地块表),其中包含可用的地块和图像,它们一并组成了可见的地图。
地块坐标
每个地块都有一个(x, y)坐标,表征其在地图上的位置。其中(0, 0)代表左上角的地块。其中x值从左到右依次增加,y值从上到下依次增加。例如:
可使用Debug Mode模组以在游戏中查看地块坐标。
地图格式
开发星露谷模组时,有两种可用的地图模式:.tmx (Tiled地图编辑器)和 .tbin(tIDE地图编辑器,已过时)。两种格式支持的功能几乎相同,但仍有一些小差异,如下:
功能 | .tmx | .tbin |
---|---|---|
格式 | ✓ XML(基本上为文本) | ✘ 二进制 |
使用Tiled编辑 | ✓ 支持 | ✓ 支持,需要插件 |
直接编辑 | ✓ 可用文本编辑器打开 | ✘ 不支持 |
地块翻转 | ✓ 支持 | ✘ 不支持 |
地块旋转 | ✓ 支持 | ✘ 不支持 |
源码管理 | ✓ 高效存储,可记录更改。 | ✘ 低效存储(每次提交均需复制完整文件),不能记录更改。 |
因此推荐使用.tmx,但两种文件都受支持,且可以通过Tiled中的 File > Export As 选项转换格式。
地块表 vs 地块集
Tilesheets(地块表)是用作贴图的.png文件。地块表不包括动画、属性、地形或与像素关联的任何东西 -- 地块表的图像只是纯粹的图像。而Tilesets(地块集)为Tiled的XML文件,其中蕴含有关地图如何使用贴图的全部信息。我们并不严格区分这两个术语。
入门
主要有两种方式编辑地图。
使用SMAPI
创建SMAPI模组需要编程,但其功能更强大,且多个SMAPI模组可以同时编辑相同地图。若希望使用此途径:
- 参见创建SMAPI模组。
- 参见下文的使用SMAPI作出更改。
此指南的余下部分假设您使用的是Tiled,但许多概念是相通的,因此您可以使用Tiled以及SMAPI(例如,创建/编辑地图相当于SMAPI中的载入/编辑地图)。
使用Tiled
Tiled是一个用于编辑星露谷地图的流行地图编辑器,不需要编程。需要解包地图的XNB文件,编辑地图,并制作一个Content Patcher或SMAPI模组以加载地图。若希望使用此方法:
- 安装Tiled最新版。
- 安装后,在界面左上角,依次点击Edit > Preferences > Plugins并启用tbin插件(在Windows上为tbin.dll,在Linux上为libtbin.so,在Mac上为libtbin.dylib)。
- 进行如下设置
设置名 值 原因 View > Snapping > Snap to Grid ✓ enabled 将物体转换为游戏的格式。 View > Highlight Current Layer ✓ enabled 使您看清当前编辑的地块。 - 参见模组:编辑 XNB 文件以学会如何打包/解包地图文件。
- 参见下述指南以学会更改地图。
(若您正在使用xnbcli来解包原始地图,则必须使用.tbin插件,无论您实际上是否在使用.tmx。这是因为xnbcli只能输出.tbin文件。)
编辑
编辑地图
重要提示:当制作自定义地图时,请先打开一个原版地图,并在其基础上编辑。不要尝试在Tiled中创建新地图;游戏必需某些地块、地图性质等。也请注意编辑或添加地图时,大于高155、宽199的尺寸会损坏图层。
- 解包游戏的Content/Maps文件夹,并创建一个副本,以在其基础上编辑地图。在将地图正式添加到您的模组的正式文件夹之前,请在此副本文件夹中编辑地图。
- 若要在非原版地图的基础上编辑,也请使用上述方法解包并将其置于您的工作文件夹。
- 使用Tiled打开.tbin或.tmx文件。注意:请确保此文件和解包的地块表位于相同的目录下!
- 作出更改。
- 保存文件。不要使用Save as选项更改保存的文件夹,否则会无法找到地块表路径。
- 将.tbin或.tmx文件及其依赖的自定义地块表移动至您的模组的正式文件夹。具体来说是放在assets文件夹。
- 通过SMAPI或ContentPatcher(或其他模组框架)加载模组。
自定义地图
您可以向游戏添加新地图或新地点。最简单的方式是使用Tiled创建地图,然后使用Content Patcher以将此自定义地点添加到游戏。在加载存档后,可以使用此控制台命令来跳转到此地图:debug warp YourLocationName X Y
。
注意地图必需按照一定模式来建造;请观摩Content/Maps文件夹中的例子。修改已经存在的地图通常比从零开始制作新地图容易得多。
亦可使用C#来自己动手添加新地点,但需要注意对象持久性和村民寻路之类的因素,它们都很容易出错。若您的确希望自己动手,则请在CreatedInitialLocations和SaveAddedLocations环节调用专门的LoadStageChanged事件以将此地点添加到Game1.locations。
添加地块集
您可以使用自定义模组或原版游戏作为地图的新贴图、地块或图像的来源。若您正在编辑原版地图,请确保自定义地块表名称具有z_
前缀,以避免改变原版的地块表索引。
- 打开您创建的或正在编辑的地图。
- 点击Map,然后点击上面菜单的 Add External Tileset... ,然后打开同一文件夹下的.tsx文件。
- 现在应当能在您的地图中看见此地块集的拷贝,同时已保存的动画、属性和地形保持不变。
复用原版地块集
假设您希望在地图中使用像spring_outdoorsTileSheet.png这样的原版地块表。为此,一种不便的方法是直接基于.png文件新建地块集:这意味您需要重新为所有需要动画的地块设置动画,以及需要重新添加所有地块属性,例如可否挖掘。(同时也会丢失原版地块集的所有地形类型。)为避免这种情况,您可以先从现有的地图导出这些信息,然后使用外部地块集,步骤如下:
- 打开一个包含所需属性和动画的现有地图。
- 在Tilesets面板,单击提示 Edit Tileset 的小按钮。这应当会打开一个新的编辑页面。
- 在打开的新窗口上点击 File , 然后点击 Export as... , 然后将其保存为.tsx文件。
- 关闭地块集编辑器。
替换现存地块集
若您已使用图片创建了地块表,则可替换其地块集:
- 打开您创建的或正在编辑的地图。
- 在右侧的Tilesets面板上,点击相应的地块表。
- 点击其下方的 Replace Tileset 小按钮。
- 选择您保存的地块集.tsx文件,并点击Open。
添加新的自定义地块集
若您正在制作自己的地块表,且正在第一次尝试将其添加到地图,则可基于此表创建新的地块集。
- 创建您的贴图集,并将其与.tbin或.tmx地图文件置于同一目录下。贴图集应当为PNG图片,其中的小贴图切成16x16像素的图块(参见模组:编辑 XNB 文件#介绍的例子)。
- 在Tiled打开地图。
- 添加自定义贴图集:
在地图上绘制地块
- 在 Layer 面板上,点击您希望编辑的图层。
- 在左上角的工具条中,点击 Stamp Brush 。
- 在 Tilesets 面板上,点击您希望使用的地块集的选项卡。
- 在 Tilesets 面板上,点击一个地块以选中它。按住并拖动鼠标可以同时选中多个地块。
- 将光标移到地图上,会发现地图上的地块与所选地块重叠了。
- 点击地图以将选中的地块放到所选图层的指定位置。
地图属性
每个地图都可有多种地图属性,这些属性定义了有关地图的特性和行为,例如光照、音乐、传送点等。每个属性都有一个名称(此名称定义了属性的类型)、一个类型(对于星露谷物语,只能为“string”)和一个值(用于配置此属性)。参见下文已知地图属性。
在Tiled中:
- 点击工具栏中的 Map 并选择 Map Properties 。
- 使用此GUI浏览和编辑地图属性。
地块属性
地块属性是对每个独立地块设置的属性。它们可以改变游戏行为(例如决定玩家可否穿过此地块),或在玩家踏上/点击此地块时完成特定动作。每个属性都有一个名称(此名称定义了属性的类型)、一个类型(对于星露谷物语,只能为“string”)和一个值。在Tiled中地块属性主要分为两种:object properties 仅作用于选中的地块,而 tile properties 作用于一个地块的所有实例。一般情况下您只需要设置 object properties , 因此下文将仅针对此进行讲解。
注意地块属性需要有与之相应的地块;若没有与之相应的地块,则不会被使用。
可用如下方法浏览地块属性:
- 在 Layers 面板选中相应的 Objects Layer 。
- 选中工具栏中的 select object 工具。
- 点击您希望浏览其数据的对象,也就是地图上的灰色选择框:
- object properties 现在会在 Properties 面板列出:
可按如下步骤编辑现有对象的属性:
可按如下步骤添加新对象:
- 选中 Layers 面板中某个 Objects Layer 。注意,每个 Tile Layer 都应拥有对应的 Objects Layer 。若某个 Tile Layer 缺失对应的 Objects Layer,则新建一个同名的 Objects Layer。
- 从工具栏选中 insert rectangle(插入矩形)工具。
- 在欲编辑的地块上点击并拖动此矩形。确保它对齐到地块网格(参见#使用Tiled),且仅选取了一个地块。
- 将其Name字段改为TileData。
- 参见上文以编辑其属性。
地块
您可以编辑现有地图的地块。参见Tiled 文档以获取更多信息。
地块动画
您可以为地块添加动画,以实现类似于吉尔坐在摇椅上的动画效果(参见右侧示例)。
在Tiled中可通过如下步骤创建动画:
- 在 Tilesets 面板选中要编辑的地块表,并点击下方的编辑按钮(扳手图标)
- 选择欲添加动画的地块。
- 点击工具栏的 Tile Animation Editor ,会打开一个动画编辑窗口。
- 将地块表中的地块拖动到动画编辑窗口内靠左的白色方框内。这会创建一个新帧。若需要删除帧,则选中此帧并按下Backspace或Delte键(Windows),或者 fn + Backspace键(Apple)。
- 双击某帧右侧的数字,以设置每帧的持续时间。单位为毫秒。请确保每帧都有相同时间;游戏不能处理每帧时间不同的情况 例如,如下是吉尔摇椅动画的动画编辑器:
- 当您完成上述步骤后,关闭先前打开的界面。
- 现在 Tilesets 面板中的动画地块应当在其右上角显示一个小符号:
这意味动画已经成为此地块的一部分了。地图上的此地块的实例现在应当显示相同的动画。
地块翻转/旋转
欲使用翻转/旋转的地块,无需在地块表中手动添加相应地块。这需要安装SMAPI 3.4 或更高版本;原版并不支持地块变换。
在Tiled中:
- 选中Stamp Brush工具后,点击地块表中欲使用的地块。
- 点击上方工具栏的 Flip(翻转)或 Rotate(旋转)按钮,它们位于工具栏右侧。
- 点击地图以放置翻转/旋转后的地块。
.tbin插件不支持地块变换。参见地图格式以获取更多信息。
高级编辑
落座非家具的椅子
玩家可以坐在嵌入在地图中的椅子。其原理如下:检查Buildings层的地块,然后把它的地块表、地块表索引与Data\ChairTiles中的数据做比对。
Data\ChairTiles中的每个字典项都有形如sheet filename/tile X/tile Y
的键名:
字段 | 描述 |
---|---|
sheet filename | 地块表的文件名,不包含文件扩展名。例如,对于从assets/some-tilesheet.png 加载的地块表,其sheet filename应当为some-tilesheet 。
|
tile X tile Y |
此地块在地块表上的X位置和Y位置。从0开始计数。 |
每个字典项的值形如width in tiles/height in tiles/direction/type/draw tile X/draw tile Y/is seasonal/alternate tilesheet
:
字段 | 描述 |
---|---|
width in tiles height in tiles |
座椅的尺寸,单位为地块。例如,设置宽度为2,则会允许玩家坐在该椅子地块右侧的地块上。 |
direction | 玩家坐下时应当面向的方向。可用的取值为down、left、right、up或 opposite。任何其他取值都会被默认为up。 |
type | 取下两者之一:
|
draw tile X draw tile Y |
绘制椅子在TileSheets\ChairTiles地块表(或自定义地块表)中的X和Y位置。从0开始计数。若宽度/高度大于1,则取左上角的地块。 |
is seasonal | 落座时是否绘制季节变体。若开启,则<draw tile X> 和<draw tile Y> 每个季节会偏移一格。这也就是说,春/夏/秋/冬贴图应当在地块表中按照从左到右的顺序相邻排列。
|
alternate tilesheet | 可选 用于绘制地块的地块表素材名称,须使用\\(双反斜杠)作为路径分隔符。默认值为TileSheets\\ChairTiles。 |
已知地图属性
建造建筑
属性 | 解释 |
---|---|
CanBuildHere T (可用于任何户外地点) |
是否允许在当前地点建造建筑。游戏会自动处理建造过程(例如罗宾会询问玩家建造位置)。 |
BuildConditions <query> (可用于任何户外地点) |
若设置了CanBuildHere,则可设置此游戏状态查询以判定当前是否可以建造于此。 |
LooserBuildRestrictions T (可用于任何户外地点) |
若设置此属性,则无需再另行设置Buildable T或Diggable T。不过,仍可以设置Buildable F以阻止建造建筑。其他限制仍会生效。 |
ValidBuildRect <x> <y> <width> <height> (可用于任何户外地点) |
可以放置建筑的地块区域。若缺省,建筑可以放置在任何可能的开放空间。 |
农作物
属性 | 解释 |
---|---|
AllowGiantCrops T | 若设为非空值,则巨大作物可以在此地块生长(前提是此地块允许种植作物,而这是由作物数据或PlantableLocations上下文字段决定的。) |
DirtDecayChance <chance>
|
每块未种作物的耕地过夜消失的概率。为 0(永不)和 1(必然)之间的值。默认为 0(温室)、0.1(农场)和 1(其他)。 |
植物、采集品和物品生成
属性 | 解释 |
---|---|
AllowGrassGrowInWinter T² (适用于任何地点) |
允许草在冬季蔓延。 |
AllowGrassSurviveInWinter T² (适用于任何地点) |
允许秋天的草在秋冬换季时不消失。 |
EnableGrassSpread T² (适用于任何地点) |
允许此地点的草每天蔓延。 |
Fall_Objects T² Spring_Objects T² Summer_Objects T² Winter_Objects T² |
是否根据Data\Locations.xnb中的数据在可用的地块上生成季节物体。 例如:Fall_Objects。 |
Feed <int x> <int y> (适用于鸡舍和畜棚) |
示例:Feed 3 2。 此Feed地图属性在1.6中已过时。现在喂料斗定义在Data/Buildings中,作为IndoorItems项“(BC)99”而出现。 |
ForceAllowTreePlanting T² (适用于任何地点) |
允许在当前位置种植树木(野树和果树),无论正常情况下是否允许种树。 |
ForceSpawnForageables T² (适用于室内) |
允许此地点生成采集品。 |
skipWeedGrowth T² (valid in any location) |
阻止杂草在此地生成和蔓延。 |
SpawnBeachFarmForage T² (适用于农场) |
在农场上随机生成海滩采集物和补给箱(就像原版的海滩农场)。仅当一个地块的Back图层具有BeachSpawn T属性、该地块为空、且在AlwaysFront层上没有地块时,采集品和补给箱才能生成于此地块。 |
SpawnForestFarmForage T² (适用于农场) |
在农场上随机生成森林采集品(就像原版的森林农场)。仅当一个地块具有Type Grass属性、该地块为空、且在AlwaysFront层上没有地块时,采集品才能生成于此地块。 |
SpawnGrassFromPathsOnNewYear T² (适用于任何地点) |
新的一年开始时,在每个Paths层上索引为22的地块上生成草。另请参阅SpawnRandomGrassOnNewYear。 |
SpawnDebrisOnNewMonth T SpawnDebrisOnNewYear T² (适用于任何地点) |
新的月/年开始时,在随机位置生成杂草、石头或数值(服从于通常情况下的生成规则)。 |
SpawnMountainFarmOreRect <tile X> <tile Y> <tile width> <tile height> (适用于农场) |
农场地图上矿石随机生成的地块区域(就像原版的山顶农场)。矿石仅会生成在具有Type Dirt地块属性的空地块上。 |
SpawnRandomGrassOnNewYear T² (适用于任何地点) |
在新的一年开始时,在随机位置生成草(依赖于通常情况下草的生成规则)。另请参见SpawnGrassFromPathsOnNewYear。 |
Stumps [<int x> <int y> <unused> ]+(适用于任何地点) |
每天向秘密森林地图添加大树桩。每个树桩的第3个字段似乎无用。 示例:Stumps 24 6 3 29 7 3 26 10 3 46 6 3 34 26 3 41 26 3。 |
Treasure <type> <int id> (适用于任何地点) |
添加能被挖掘的宝藏。其中<type> 取下列值之一:Coins, Copper, Coal, Iron, Gold, Iridium, CaveCarrot, Arch, Object。 若设为Arch或Object,则可指定 <id> 以指定宝藏物品的ID。
|
Trees [<int x> <int y> <int type> ]+(适用于任何地点) |
向地图添加树。其中 <x> <y> 字段为地块坐标,而 <type> 为树的类型( 0:橡树,1:枫树,2:松树,5:棕榈树,6:磨菇树,7:桃花心木)。示例:Trees 17 18 2 20 31 2。 |
传送和地图位置
属性 | 解释 |
---|---|
AllowWakeUpWithoutBed <allow>
|
玩家是否能够不用床便在此位置醒来,类似于姜岛农舍。这主要与Data/LocationContexts的PassOutLocations字段配合使用。 |
BackwoodsEntry [<int x> <int y> ](适用于农场) |
玩家从边远森林进入农场时被传送到的位置。 |
BusStopEntry [<int x> <int y> ](适用于农场) |
玩家从巴士站进入农场时被传送到的位置。 |
DefaultWarpLocation <x> <y> (适用于任何地点) |
默认的目的地地块,当玩家或村民被添加到此地点却未指定目标地块时,则会默认传送到此地块。(使用调试命令,例如debug warp或debug eventbyid就会造成这种情况。) |
EntryLocation <tile X> <tile Y> (适用于农舍) |
设置玩家进入农舍时被传送到的地块。 |
FarmCaveEntry [<int x> <int y> ](适用于农场) |
玩家从农场山洞回到农场时被传送到的地点。 |
FarmHouseEntry [<int x> <int y> ](适用于农场) |
更改农舍的位置。也就是会更改农舍入口和出口的位置。 |
ForestEntry [<int x> <int y> ](适用于农场) |
玩家从煤矿森林进入农场时被传送到的位置。 |
GrandpaShrineLocation [<int x> <int y> ](适用于农场) |
爷爷的神龛的位置。对应于其左上角地块。 |
GreenhouseLocation [<int x> <int y> ](适用于农场) |
温室的默认位置。对应于温室左上角地块的位置。 |
KitchenStandingLocation [<int x> <int y> ](适用于农舍) |
使用厨房时玩家的配偶站立的位置。 |
MailboxLocation [<int x> <int y> ](适用于农场) |
玩家邮箱的位置。对应于邮箱的左上角地块。 |
NPCWarp [<int fromX> <int fromY> <string toArea> <int toX> <int toY> ]+(适用于任何地点) |
相当于Warp,但仅适用于村民。 |
PetBowlLocation <x> <y> (valid in the farm) |
宠物碗的默认位置。 |
ShippingBinLocation [<int x> <int y> ](适用于农场) |
出货箱的默认位置。对应于出货箱左上角地块。 |
SpouseAreaLocation [<int x> <int y> ](适用于农场) |
室外的4x4的配偶使用的区域。对应于该区域左上角地块。 |
SpouseRoomPosition <x> <y> (适用于农舍) |
用于放置配偶的房间的位置,对应于配偶房间的左上角地块。 |
TravelingCartPosition <x> <y> (适用于煤矿森林) |
用于放置旅行货车的位置,对应于货车左上角。此处的左上角为碰撞箱的左上角,因此货车车篷会高于此地块2格。 |
Warp [<int fromX> <int fromY> <string toArea> <int toX> <int toY> ]+(适用于任何地点) |
设置用于传送玩家到另一地图的地块(例如们)。其中 <fromX> <fromY> 字段是传送点的地块坐标,<toArea> <toX> <toY> 为待去往地点的名称和传送目标地块的坐标。示例: 6 20 Mountain 76 9。 |
WarpTotemEntry[<int x> <int y> ](适用于农场) |
当玩家通过农场图腾或回程魔杖传送回农场时使用的位置。 |
音频
属性 | 解释 |
---|---|
BrookSounds [<int x> <int y> <int type> ](适用于室外) |
添加声源。其中 <x> <y> 字段为地块坐标,<type> 为背景音ID,其取值如下:
|
Music <string name> (适用于任何地点) |
设置玩家进入此地图时播放的音乐,其中<name> 为音频文件中的声音提示名称。示例:Music MarlonsTheme。(已过时;请使用Data/Locations中的音乐字段。仅当Data/Locations没有音乐时才使用此属性。) |
Music <int start> <int end> <string name> (适用于任何地点) |
设置玩家进入此地图时播放的音乐,其中<name> 为音频文件中的声音提示名称。音乐只会在游戏时间介于 <int start> (含)和 <int end> (不含)时播放。示例:Music 800 1200 MarlonsTheme. (已过时;请使用Data/Locations中的音乐字段。仅当Data/Locations没有音乐时才使用此属性。) |
光照
属性 | 解释 |
---|---|
AmbientLight <byte r> <byte g> <byte b> (适用于室内和忽略室外光照的地点) |
设置环境光照的RGB颜色。特别注意,此颜色值为白色 (255,255,255) 减去欲设置颜色的RGB值。 示例: AmbientLight 95 95 95设置正常情况下白天的室内光照。 |
AmbientNightLight <byte r> <byte g> <byte b> (适用于室内和忽略室外光照的地点) |
设置夜间环境光照的RGB颜色。特别注意,此颜色值为白色 (255,255,255) 减去欲设置颜色的RGB值。 示例:AmbientLight 150 150 30 设置温室的夜间环境光照。 |
forceLoadPathLayerLights T² 适用于室外非节日地点 |
是否强制从Paths层加载地图光照,正常情况下不会从此处加载光照。 示例: forceLoadPathLayerLights true. |
IgnoreLightingTiles T² (适用于室内) |
是否忽略Front和Buildings层的光照。 示例: IgnoreLightingTiles true。 |
Light [<int x> <int y> <int type> ]+(适用于任何地点) |
添加光源。其中<type> 字段为光源种类(例如4代表壁挂烛台),而 <x> <y> 则为地块坐标。其中<type> 可能的取值为:
其他取值会使游戏崩溃。 |
WindowLight [<int x> <int y> <int type> ]+(适用于任何地点) |
添加仅在非雨天室内点亮的光源(例如窗户阳光)。参见Light以获得详细信息。 |
地图和地块更改
属性 | 解释 |
---|---|
ClearEmptyDirtOnNewMonth T² (适用于任何地点) |
在新的一年开始时,清除所有未种作物的耕地。 |
DayTiles [<string layerName> <int x> <int y> <int tilesheetIndex> ]+(适用于任何地点) |
设置早6时至晚7时出现的地块。晚7时前,此属性会自动寻找<layerName> 层中的、位于坐标 (<x> , <y> ) 处的地块,将满足条件地块的地块表索引设为<tilesheetIndex> ,并添加辉光以模拟日光。仅当地点在室内且<tilesheetIndex> 为256、288、405、469或1224会添加辉光。可传入多组参数以同时配置多组地块。示例: DayTiles Front 3 1 256 Front 3 2 288。 |
NightTiles [<string layerName> <int x> <int y> <int tilesheetIndex> ]+(适用于任何地点) |
在晚7时后改变地块。此外,此属性经常搭配DayTiles使用:早6时到晚7时使用DayTiles地块,在晚7时后使用NightTiles的地块。游戏中,此属性主要用于台灯。注意夜间时间依赖于季节(游戏内时间#日落)。 |
Doors [<int x> <int y> <string sheetID> <int tileID> ]+(适用于室内) |
配置室内门的功能。与Action Door地块属性搭配使用。 其中 <x> <y> 字段为地块坐标,<sheetID> 为包含门贴图的贴图集名,而 <tileID> 为贴图集内的地块索引。
|
钓鱼
属性 | 解释 |
---|---|
FarmFishLocationOverride <location name> <chance> (适用于农场) |
钓鱼时添加一个备选地点名称,其中<chance> 为 0(不可能)至 1(必然)之间的小数值。例如,FarmFishLocationOverride Mountain 0.5在当前地点增加50%概率抓到深山鱼类而非普通鱼类。地点名称是大小写敏感的,可由Debug Mode模组给出。
|
FarmOceanCrabPotOverride T² (适用于农场) |
使农场的蟹笼能抓到海鱼。 |
农舍内部
属性 | 解释 |
---|---|
FarmHouseFlooring <flooring id> (适用于农场) |
创建新存档时,设置农舍初始地板样式。地板ID映射到Maps/walls_and_floors地块表中从索引336开始的4x4区域(其中地板ID 0 被映射到左上角的地板)。 |
FarmHouseFurniture [<furniture ID> <tile X> <tile Y> <rotations> ]+(适用于农场) |
创建新存档时,生成初始家具。若在同一地块上添加多个家具,则第一个家具会被放在地上,而最后一个家具会被放在第一个家具上。 |
FarmHouseStarterGift [<id> [count] ]+
|
创建新存档时,应当出现在礼盒中的物品。参数由一到多组“物品ID 物品数量”对组成。其中最后一组物品的数量是可选的。
例如,下述代码会生成10条河豚(物体128)和一个水滴鱼面具(帽子56): FarmHouseStarterGift (O)128 10 (H)56 1 若缺省,则会添加默认物品(通常为15个防风草种子)。 |
FarmHouseStarterSeedsPosition <tile X> <tile Y> (适用于农场) |
设置创建新存档时种子包的放置位置。 |
FarmHouseWallpaper <wallpaper id> (适用于农场) |
创建新存档时,设置农舍初始墙纸样式。墙纸ID映射到Maps/walls_and_floors中从左上角开始数的1x4区域。 |
其他地点元数据
属性 | 解释 |
---|---|
CanCaskHere T² (适用于任何地点) |
允许木桶在此地点工作。 |
indoorWater T² (适用于室内) |
允许此地点的水体逻辑(即钓鱼等)。 |
IsFarm T² (适用于任何地点) |
将此地点标记为农场。仅影响那些会检查游戏代码中location.IsFarm 属性的通用地点/互动逻辑;而那些硬编码到Farm 类的逻辑(例如农场动物、宠物、乌鸦、稻草人、温室、农场建筑等)仍然只能用于真正的农场。
|
IsGreenhouse T² (适用于任何地点) |
将此地点标记为温室。 |
LocationContext Default (适用于任何地点) |
将地图设置为星露谷地区的一部分,以使用特定的游戏逻辑,比如天气。 |
LocationContext Island (适用于任何地点) |
将地图设置为姜岛地区的一部分,以使用特定的游戏逻辑,比如天气。 |
Outdoors T² (适用于任何地点) |
设置此区域是否为室外。 示例: Outdoors true。 |
ProduceArea <int x> <int y> <int width> <int height> (valid in coops and barns) |
设置动物能出生在鸡舍或畜棚中的区域。 示例: ProduceArea 6 4 8 7。 |
ScreenshotRegion <int left> <int top> <int right> <int bottom> (适用于任何地点) |
限制截图时地图渲染的区域。 示例: ScreenshotRegion 0 27 69 61。 |
SeasonOverride [<string season> ](适用于任何地点) |
为大多数游戏检查设定一个特殊的季节,这些检查包括可否种植作物、使用何种地块表等。 |
TreatAsOutdoors T² (适用于室内) |
此地点会被视作室外,这会产生如下效果:生成除了Paths层光照以外的东西,打碎石头产出煤炭。 示例: TreatAsOutdoors true。 |
UniquePortrait [<str name> ]+(适用于任何地点) |
根据当前地点将指定NPC的肖像切换为相应的变体。例如例如村民Jane位于地点Room,则会将肖像切换到Portraits/Jane_Room。 示例: UniquePortrait Maru。 (已过时;请使用自定义村民外观取代之。这些属性会重写NPC外观。) |
UniqueSprite [<str name> ]+(适用于任何地点) |
根据指定的村民将当前地点的贴图集切换为相应的变体。例如村民Jane位于地点Room,则会将贴图集切换到Characters/Jane_Room。 示例: UniqueSprite Maru。(已过时;请使用自定义村民外观取代之。这些属性会重写NPC外观。) |
ViewportClamp <int x> <int y> <int width> <int height>
|
阻止视窗移出指定区域之外。 示例: ViewportClamp 10 0 35 30(用于巴士站地图,使得左上角能看到的最远地块为 10, 0 而右下角能看到的最远地块为 44, 29 。) |
ViewportFollowPlayer T² (适用于任何地点) |
强制视窗以玩家为中心。 示例: ViewportFollowPlayer。 |
¹ 地图属性主要由GameLocation类的各种方法处理,尤其是resetLocalState。
² T值(也就是 true 的缩写)只是惯例,实际上亦可传入任意非空值。
已知地块属性
本节不包括那些非常专门的属性,例如TouchAction WomensLocker。¹
概述
图层 | 属性 | 解释 |
---|---|---|
Back | BeachSpawn T² | 使用海滩农场类型时,允许此地块生成海滩采集品和补给箱。 |
Back | Bed T² | 若玩家站在此地块上,则其会被认为正在床上,以用于体力回复(多人游戏中)以及晕倒逻辑。 |
Back | Buildable T² | 若无其他障碍,允许在此地块上建造农场建筑。 |
Back | DefaultBedPosition T² | 用于在升级后的农舍中放置玩家床铺,以及在迁移存档时使用。 |
Back | DefaultChildBedPosition T² | 用于在升级的农舍中放置婴儿床。 |
Back | Diggable T² | 将此地块标记为可被锄头挖掘和可以种植作物。也允许草在此地块上生长。 |
Back | NoFishing T² | 禁止玩家在钓鱼时在此地块抛竿。 |
Back | NoFurniture T² | 禁止玩家在此地块上放置物体(不仅包括家具)。 |
Back | NoPath | 禁止村民穿过此地块。使村民必要时绕过此地块。 |
Back | NoSpawn All NoSpawn True |
结合了NoSpawn Grass和NoSpawn Tree。 |
Back | NoSpawn False | 禁用此地块先前设置的所有NoSpawn属性。例如,可以用此属性来取消一个地块先前设置的NoSpawn地块索引属性。 |
Back | NoSpawn Grass | 禁止杂物(例如杂草或石头)生成在此地块。 |
Back | NoSpawn Tree | 禁止树在此生成。禁止玩家在此植树(除非在农场上)。若此地块已有树,禁止树在此生长。 |
Back | NoSprinklers T² | 禁止在此放置洒水器。 |
Back | NPCBarrier T² | 用于农场(包括鸡舍、畜棚、史莱姆屋)、地下矿井或姜岛,可禁止村民穿过或生成于当前地块。 |
Back | Passable T² | 禁止玩家在此地块上行走或放置东西,无论正常情况是否允许(正好与Buildings层的Passable T属性相反)。通常用于特定的水体地块上以划定桥的边界,从而防止玩家走入水中。既可以作为独立的TileData对象添加到地图中特定的地块上,也可以通过编辑地块表,将该属性直接添加到地块索引上,从而将此属性批量应用于此地块的实例。后一种方式更常用。 |
Back | TemporaryBarrier T² | 仅在门打开的瞬间有用。会使玩家不可通过此地块,而村民则会认定该地块为障碍物而暂停后快速通过。 |
Back | Type <str type>
|
设置地块类型,以用于多种游戏逻辑(例如脚步音效或种植作物),其中<type> 取 Dirt 、Stone 、Grass 或 Wood 之一。
|
Back | Water T² | 将地块标记为水体地块,以用于多种游戏逻辑(即:物品会落入水中;可灌满喷壶;可能允许钓鱼;可能允许蟹笼;可灌溉附近水田作物;大部分情况不会被认作空地块;若在室内则可用于回复生命;若在室内、室外、矿井、下水道、潜水艇中则绘制动态的水波纹图,若在沙漠中则不绘制。
将属性值设定为 I(大写字母)会使得地块不渲染水波纹。 |
Back | WaterSource T² | 允许玩家在此地块灌满喷壶。 |
Buildings | LockedDoorMessage <string data asset path>
|
用于在未满足ConditionalDoor条件时显示一个对话框,其文本取自指定的数据素材。 示例:LockedDoorMessage Strings\\\\1_6_Strings:guild_door |
Buildings | NPCPassable T² | 相当于仅对村民有效的Passable属性,见下文。允许村民穿过此地块。 |
Buildings | Passable T² | 允许穿过此地块,无论此地块正常情况下能否穿过。常用于Buildings层的、架在水上的小桥。此属性正好与上文的Back Passable T相反。既可以作为独立的TileData对象添加到地图中特定的地块上,也可以通过编辑地块表、将该属性直接添加到地块索引上以将此属性批量应用于此地块的实例。后一种方式更常用。 |
Buildings | ProjectilePassable T² | 允许抛射物穿过正常情况下无法穿过的地块(例如允许向岩浆池中射击)。 |
Buildings | Shadow T² | 相当于上文的Passable属性,但仅用于玩家。允许玩家穿过此地块而不允许村民。 |
Paths | Order <I>
|
此属性应当施用于Paths地块表的29和30索引处。此属性设置多人游戏中联机小屋的生成顺序。 |
Paths | SpawnTree <type> <ID> [stage on spawn] [stage on regrow]
|
创建地图时生成一棵树。其中:
此地块在Paths地块表中的索引必须为34。 |
TouchAction
TouchAction属性规定了玩家踏在地块上时执行的操作。
图层 | 属性 | 解释 |
---|---|---|
Back | TouchAction ChangeIntoSwimsuit | 使玩家换上泳装,禁止奔跑。 |
Back | TouchAction ChangeOutOfSwimsuit | 使玩家换上常服,允许奔跑。 |
Back | TouchAction ConditionalDoor <query>
|
使用游戏状态查询来确定玩家是否可以通过此地块。 若此地块同时具有LockedDoorMessage属性,且前述状态查询未通过,则会显示LockedDoorMessage所指定的文本;若未指定前述属性,则会显示默认的“It's locked...”对话框。 示例: ConditionalDoor PLAYER_STAT Current monstersKilled 1000 |
Back | TouchAction DesertBus | 允许在此乘公交返回巴士站。 |
Back | TouchAction Emote <string npc> <int emoteID>
|
寻找姓名符合<npc> 字段的村民,并使其头顶显示<emoteID> 对应的表情(4:罐子,8:问号,12:生气,16:叹号,20:爱心,24:睡觉,28:伤心,32:开心,36:否定,40:愣住,52:游戏,56:音符,60:尴尬)。
|
Back | TouchAction FaceDirection <string npc> <int direction>
|
寻找姓名符合<npc> 字段的村民,并使其面部朝向给定方向(0:上,1:右,2:下,3:左)。
|
Back | TouchAction legendarySword | 当玩家手持五彩碎片时,给予其银河剑。 |
Back | TouchAction MagicWarp <string area> <int x> <int y> [string prerequisite]
|
将玩家传送到<area> 区域的<x> <y> 地块坐标处,并产生魔法音效和特效。若指定了[prerequisite] 字段,则仅当此字段指定的标识已被Game1.player.mailReceived设定才会传送。
|
Back | TouchAction PlayEvent <event id> [check preconditions] [skip if seen] [fallback action]
|
相当于Action PlayEvent,但在玩家踏上此地块才触发。注意[fallback action] 是一个Action地块属性,而非 TouchAction地块属性。
|
Back | TouchAction PoolEntrance | 切换玩家走路/游泳模式。 |
Back | TouchAction Sleep | 经玩家确认后在此睡觉。 |
Back | TouchAction Warp <string area> <int x> <int y> [string prerequisite]
|
在此添加传送到指定地点和位置的传送口,仅用于玩家。此属性完全等价于TouchAction MagicWarp,除了没有魔法音效/特效。 |
Action
Action属性使得玩家与地块交互(例如,点击)时触发某种动作:
图层 | 属性 | 解释 |
---|---|---|
Buildings | Action AdventureShop | 显示探险家公会的商店界面。 |
Buildings | Action Arcade_Prairie | 显示“草原王者大冒险”街机游戏。 |
Buildings | Action Arcade_Minecart | 显示“祝尼魔赛车”街机游戏。 |
Buildings | Action BuyBackpack | 显示一个让玩家升级背包的菜单(若相应升级可用)。 |
Buildings | Action Billboard | 显示日历菜单。 |
Buildings | Action Blacksmith | 若克林特在附近,打开克林特的商店菜单。 |
Buildings | Action Buy | 用在皮埃尔的杂货店中,当皮埃尔在附近(或去往姜岛而留下收钱箱)时,打开杂货店菜单。用在桑迪的商店中,则当桑迪在附近时打开桑迪商店的菜单。用于其他地点无效。 |
Buildings | Action BrokenBeachBridge | 提示玩家使用木材修桥。 |
Buildings | Action BuildingSilo | 若此地块上有建筑,则根据Data/Buildings中此建筑的HayCapacity字段启用该地块上的筒仓交互。 |
Buildings | Action BuildingToggleAnimalDoor | 若此地块上有建筑,打开或关闭其动物门。 |
Buildings | Action BuyQiCoins | 显示一个让玩家购买100齐币的对话。 |
Buildings | Action Concessions | 打开电影院中的小卖部菜单(仅在电影院内有效)。 |
Buildings | TouchAction ConditionalDoor <query>
|
用于室内门下方的地块。此属性利用一个游戏状态查询以检查玩家是否可以打开此门。若检查未通过且此地块具有LockedDoorMessage属性,则会显示内容为相应文本字符串的对话框;否则显示通用的"It's locked..."对话框。 示例: ConditionalDoor PLAYER_STAT Current monstersKilled 1000 |
Buildings | Action Carpenter | 当罗宾在附近时打开木匠商店的菜单。 |
Buildings | Action ColaMachine | 询问玩家是否购买Joja可乐。 |
Buildings | Action ClubCards Action Blackjack |
显示卡利科杰克小游戏。 |
Buildings | Action ClubComputer Action FarmerFile |
显示包含游戏统计数据的对话框(步数、送出的礼物、挖掘的泥土等)。 |
Buildings | Action ClubSeller | 显示一个对话框询问玩家是否以1,000,000金购买无尽财富之雕像。 |
Buildings | Action ClubShop | 显示赌场商店菜单。 |
Buildings | Action ClubSlots | 显示老虎机小游戏。 |
Buildings | Action Dialogue <text>
|
显示包含指定文本的通用对话框。参见对话格式。 示例: Action Dialogue Hi there @! |
Buildings | Action DivorceBook | 根据玩家当前婚姻状态,显示离婚选项(好比点击了离婚登记书一样)。 |
Buildings | Action Door <npcName> [npcName]
|
设置一扇室内门,除非玩家与给定村民有2心及以上的友谊,否则不能打开。门占上下两个地块,此属性需设置在下方的地块上。参见对话格式。 示例: Action Door Abigail |
Buildings | Action DropBox <ID>
|
允许玩家将物品放入此地块,用于给定<ID> 的特别任务期间的收货箱。
|
Buildings | Action ElliottBook | 显示文本 Blank book 。 |
Buildings | Action ElliottPiano | 播放四种钢琴音符之一。ElliottPiano 1 为最低音,而 ElliottPiano 4 为最高音。 |
Buildings | Action EnterSewer | 若已获得钥匙,则将玩家传送至下水道。 |
Buildings | Action EvilShrineLeft | 需要一个五彩碎片以将孩子变成鸽子。 |
Buildings | Action EvilShrineCenter | 抹除前配偶对玩家的记忆。 |
Buildings | Action EvilShrineRight | 切换农场怪物生成状态。 |
Buildings | Action Forge | 打开锻造菜单。 |
Buildings | Action Garbage <ID>
|
基于<ID> 随机给予玩家特定物品。每日只能点击一次。TODO: 解释<ID> 的作用。
|
Buildings | Action Gunther | 打开博物馆菜单,也就是可以选择捐赠古物或收集奖励的菜单。 |
Buildings | Action HMTGF | 在玩家手持大海参时给予其一个“??HMTGF??”。 |
Buildings | Action IceCreamStand | 若当前为夏季,则显示冰激凌摊界面。否则,玩家会被告知夏天再来。(需要村民站在地块后)。 |
Buildings | Action JojaShop | 显示Joja超市界面。 |
Buildings | Action Jukebox | 显示点唱机菜单以选取背景音乐。 |
Buildings | Action kitchen (适用于任何地点) |
显示烹饪菜单。 |
Buildings | Action Letter <string messageKey>
|
以信件方式呈现指定信息,该信息读取自 Content\Strings\StringsFromMaps.xnb 文件的<string messageKey> 信件键。语法与模组:信件数据相同。
|
Buildings | Action LockedDoorWarp [<int toX> <int toY> <string toArea> <int openTime> <int closeTime> <NPC> <friendship> ]
|
常用于给门设置一个开放时段。注意必须使用24小时制,即,2000代表20:00。若指定最后两个参数,则在时间限制的基础上添加友谊限制。 示例: 7 9 LeahHouse 1000 1800 Leah 500 |
Buildings | Action LuauSoup | 在夏威夷宴会上,此地块用于将食材放入汤中。 |
Buildings | Action MagicInk | 将魔法墨水添加至钱包。 |
Buildings | Action Mailbox | 显示玩家邮箱中的下一封信(如有)。 |
Buildings | Action Message <string messageKey>
|
从 Content\Strings\StringsFromMaps.xnb 中的指定键中加载信息,并显示在对话框中。 |
Buildings | Action MessageOnce <int eventID> <string message>
|
若玩家未观看过指定<eventID> 的时间,则标记此事件已被看过,并在对话框中显示指定消息文本。此属性不支持解析对话格式。
|
Buildings | Action MessageSpeech <string messageKey>
|
相当于Action Message,但将光标替换为对话光标。 |
Buildings | Action MineSign <string message>
|
显示一个小对话框,包含指定的消息原始文本。此属性不支持解析对话格式。 |
Buildings | Action MinecartTransport | 显示矿车目的地菜单(或在矿车未解锁时显示提示信息)。 |
Buildings | Action MineElevator | 若玩家已经到达矿井5层以上,则显示矿井电梯菜单(以传送至某一层),否则显示矿井电梯未工作的提示信息。 |
Buildings | Action NextMineLevel | 将玩家传送至矿井下一层(若不在矿井中,则传送到矿井1层)。 |
Buildings | Action None | 什么也不做。用于在点击动作被另行处理的情况下,将此地块标记为可交互地块。 |
Buildings | Action Notes <int noteID>
|
若玩家找到了指定的遗失之书,则显示其博物馆说明文本,并标记其为已读。 示例: Action Notes 17 |
Buildings | Action NPCMessage <str name> "<str dialogueKey> "
|
若指定村民距玩家14格以内,则从指定字符串文件的指定键处读取对话,并将此对话显示在对话框中。 示例: Action NPCMessage Abigail "Strings\\StringsFromCSFiles:Event.cs.1022" |
Buildings | Action ObeliskWarp <location name> <x> <y> [whether to dismount]
|
将玩家传送至指定地点和位置,并产生传送图腾特效和音效。 |
Buildings | Action OpenShop <shop id> [from direction] [open time] [close time] [owner tile area]
|
打开指定<shop id> 的商店。除了ID以外的所有参数均可选:
|
Buildings | Action PlayEvent <event id> [check preconditions] [skip if seen] [fallback action]
|
立即开启一个服从如下条件的事件:
若地块因为任何原因(包括事件前提)未能启动,则:
例如, |
Buildings | Action playSound <str cueName>
|
播放具有指定名称的音效或音乐。 |
Buildings | Action QiCoins | 当玩家没有齐币时,显示一个对话框以询问玩家是否购买10齐币,否则显示玩家现有的齐币数。 |
Buildings | Action Saloon | 当格斯在附近时,打开餐吧菜单。 |
Buildings | Action SandDragon | 用于“神秘的齐”任务的第三步“沙之巨龙的最后一餐”。 |
Buildings | Action Shop | 用于节日地图,打开节日商店。对非节日地图无效。 |
Buildings | Action Theater_BoxOffice | 若已解锁电影院,打开电影院的售票菜单。 |
Buildings | Action TownMailbox <ID>
|
TODO: 此地块属性的功能有待研究。 |
Buildings | Action Warp <int x> <int y> <str area>
|
将玩家传送到<area> 游戏地点的<x> <y> 的地块坐标。示例: Action Warp 76 9 Mountain |
Buildings | Action WarpCommunityCenter | 若玩家已解锁社区中心,则将玩家传送到那里(否则显示“上锁了”消息)。 |
Buildings | Action WarpGreenhouse | 若玩家已解锁温室,则将玩家传送到温室内部,否则显示关于温室废墟的消息。 |
Buildings | Action WizardBook | 若解锁,则可从此地块购买法师建筑。 |
Buildings | Action WizardHatch | 若玩家与法师友谊值足够高,则将玩家传送到法师塔地下室,否则会被告知不能进入。 |
Buildings | Action WizardShrine | 显示法师塔的幻觉神龛菜单。 |
¹ 地块属性在游戏代码中由GameLocation::doesTileHaveProperty.=处理。Action和Touch Action则分别由GameLocation::performAction和GameLocation::performTouchAction处理。表情ID则被列为Character常量。
² T值(也就是 true 的缩写)只是惯例,实际上亦可传入任意非空值。
自定义Action
C#模组可以处理自定义Action和TouchAction地图属性。这是通过调用GameLocation.RegisterTileAction和RegisterTouchAction方法,并向其传入一个接受地点、地图属性参数、激活玩家、地块位置的回调函数实现的。
例如,假设您希望创建一扇需要自定义钥匙解锁的门。您可以添加一个自常规的TouchAction Example.ModId_UnlockGate
地图属性(例如直接在地图文件中添加,或通过Content Patcher的EditMap添加,或通过模组:制作指南/APIs/Content/Content API添加)。然后,可以按如下方法使用C#模组处理此逻辑:
示例 |
---|
internal class ModEntry : Mod
{
/// <inheritdoc />
public override void Entry(IModHelper helper)
{
GameLocation.RegisterTouchAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
}
private void HandleUnlockGate(GameLocation location, string[] args, Farmer player, Vector2 tile)
{
const string mailFlag = "Example.ModId_GateUnlocked";
const string keyId = "Example.ModId_GateKey";
// unlock gate if locked
if (!player.mailReceived.Contains(mailFlag))
{
if (!Game1.player.Items.ContainsId(id, count))
{
Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
return;
}
player.removeFirstOfThisItemFromInventory(keyId);
player.mailReceived.Add(mailFlag);
}
// apply open-gate map edit
// NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
// (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
// AssetRequested event to apply the change when the map is reloaded.
IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
mapHelper.PatchMap(
this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
targetArea: new Rectangle((int)tile.X - 1, (int)tile.Y - 1, 2, 2)
);
}
}
|
作为另外一个例子,假设您希望玩家按下功能键时门会解锁。您可以添加一个自常规的Action Example.ModId_UnlockGate
地图属性(例如直接在地图文件中添加,或使用Content Patcher的EditMap添加,或使用模组:制作指南/APIs/Content/Content API添加)。然后,可以按如下方法使用C#模组处理此逻辑:
示例 |
---|
internal class ModEntry : Mod
{
/// <inheritdoc />
public override void Entry(IModHelper helper)
{
GameLocation.RegisterTileAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
}
private bool HandleUnlockGate(GameLocation location, string[] args, Farmer player, Microsoft.Xna.Framework.Point point)
{
const string mailFlag = "Example.ModId_GateUnlocked";
const string keyId = "Example.ModId_GateKey";
// unlock gate if locked
if (!player.mailReceived.Contains(mailFlag))
{
if (!Game1.player.Items.ContainsId(id, count))
{
Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
return false;
}
player.removeFirstOfThisItemFromInventory(keyId);
player.mailReceived.Add(mailFlag);
}
// apply open-gate map edit
// NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
// (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
// AssetRequested event to apply the change when the map is reloaded.
IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
mapHelper.PatchMap(
this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
targetArea: new Rectangle((int)point.X - 1, (int)point.Y - 1, 2, 2)
);
return true;
}
}
|
道路层
Paths层具有来自paths地块表的图标地块,后者会影响地图上的游戏行为:
地块索引 | 解释 | 限制 |
---|---|---|
0–6 | 未使用。村民会根据地块类型自动寻路以到达日程中的目的地。早期版本中这些地块绘有方向箭头,但1.6版本更新擦除了这些箭头。 | |
7 | 用于配偶房间、配偶露台和电影院,以标记村民应当站立的位置。可以在TileData中添加一个"direction"属性。 | 用于配偶区域和电影院。 |
8 | 添加此地块到光源类型为4(烛台)的Light地图属性。 | 仅用于室内和节日²。 |
9–12 | 在地点被创建后生成一棵树。农场外的树每天有50%的概率再生(另见31-32)。 可用树种:橡树(9)、枫树(10)、松树(11)、棕榈树1(12)。 |
仅用于室外。 |
13–18 | 在地点被创建后生成杂物。之后每天随机生成。用于农场室外,每天春季再生。 可用杂物:季节性杂草(13–15)、 石头(16–17)、树枝(18)。 |
仅用于室外。 |
19 | 在农场被创建后生成大圆木,此地块指示大圆木的左上角。 | 仅用于农场。 |
20 | 在农场被创建后生成圆石,此地块指示圆石的左上角。 | 仅用于农场。 |
21 | 在农场被创建后生成大树桩(对于森林农场而言,其后每天都会再生),此地块指示大树桩的的左上角。 | 仅用于农场。 |
22 | 在地点被创建后生成草。并在其后随机生成。 | 仅用于室外。 |
23 | 在地点被创建后随机生成2-3生长阶段的橡树、枫树或松树。 | 仅用于室外。 |
24–26 | 在地点被创建后生成通常的灌木。中型灌木会结黑莓和美洲大树莓。 可用灌木:大型(24)、中型(25)、小型(26)。 |
仅用于室外。 |
27 | 在地点被创建后,将此地块添加到babblingBrook音效对应的BrookSounds地图属性。 | 仅用于室外。 |
28 | 在此处生成一条蛆(每日有33%的概率,除非地图已经有50条蛆)。 | 仅用于突变虫穴。 |
29–30 | 在合作模式中根据布局(29=附近 30=独立)和Order地块属性生成联机小屋,此地块指示小屋的左上角。 | 仅用于农场。 |
31–32 | 在地点被创建后生成一棵树。农场外的树每天有50%几率再生(参见9-12)。 可用树木:棕榈树2(31)、桃花心木(32)。 |
仅用于室外。 |
33 | 在地点被创建后生成一棵金色核桃灌木。 | 仅用于室外。 |
34 | 启用此地块的SpawnTree地块属性,以允许野树/果树的生成/再生。 | 仅用于室外 |
35 | 对游戏无效。仅在编辑地图时用于指示地块(例如,跟踪设置了地块属性的地块)。 | |
36 | 在创建存档时生成蓝草。此后也会随机生成蓝草。 | 仅用于室外。 |
说明:
- 在突变虫穴种,每日杂物生成率下调至33%。
- 限制条件可以被forceLoadPathLayerLights地图属性覆盖。
潜在问题
地块表顺序
当您替换原版地图时,请勿更改原版地块表的顺序或ID。请在原版地块表的ID前面添加z_
以避免改变原始顺序。
- 为何这可能导致出错
- 举例而言,假设您在Tiled种替换了一张通常具有如下地块表的地图:
- 当您添加新地块表时,注意地块表顺序从[paths, untitled tile sheet]变为了[customSheet, paths, untitled tile sheet]:
- 若游戏试图从第一张地块表中获取地块,则会从customSheet地块表获取,而非按预期从Paths中获取。这可能出错,包括视觉故障(例如显示错误的地块贴图)或直接崩溃(尤其是错误地块表比预期的地块表要小时)。
- 为避免此问题,请总保持原始地块表顺序不变,并向新地块表添加
z_
前缀,使新添加的地块表总位于最后。
- 如何修复受影响的地块表。
- 参见下文的"mod reordered the original tilesheets"。
原版地块表的本地拷贝
当您在Tiled中编辑地图时,可能需要将诸如path.png或spring_town.png的原版地块表复制到地图文件夹以便Tiled使用。若加载游戏时,这些复制的地块表仍然在地图文件夹中,则可能产生非预期的效果(例如,重新着色模组的编辑将不会对您的地图奏效)。
为避免此问题,可采取如下方式之一:
- 在测试或发布模组前,从模组文件夹删除原版地块表。
- 将地块表文件重命名,使之以点号开头(例如.spring_town.png)并引用此地块表。当SMAPI在游戏中加载此地图时,它会自动忽略点号,并在Content/Maps目录下火在本地文件中寻找spring_town.png文件。
地图特有问题
游戏会假定地图满足某些性质,如果模组地图不满足这些性质,则可能出错。下面是已知的问题:
受影响的地图 | 问题 |
---|---|
Maps/Farm Maps/Farm_Combat Maps/Farm_Fishing Maps/Farm_Foraging Maps/Farm_Mining |
|
Maps/FarmHouse* |
|
Maps/SpouseRooms |
|
- ↑ 草音效设置于Grass::loadSprite方法。若Paths层具有索引22地块,则GameLocation::loadObjects会调用前述方法。(游戏会为每个索引22地块生成一个草,并随后移除它们)。
Tiled中的“Save as”
当您在Tiled中使用 'save as' ,请不要另存到其他文件夹。否则地块表引用仍然指向旧文件夹,因此地图无法正常工作。如需另存,请将全部地图文件复制/移动到另一文件夹。
在Tiled中定位地块表
当一张地图地块表缺失时,请不要使用locate选项从其他目录加载地块表。否则会生成一个复杂的地块表路径,游戏无法处理此。正确的做法是将地块表拷贝到地图所在目录,然后再引用它们。
故障排除
另见上文潜在问题以了解常见问题。
"Tilesheet paths must be a relative path without directory climbing (../)"
- 这是什么意思?
- 您的地图使用了根目录以外的地块表。产生这种情况的原因可能包括:在Tiled中使用了"save as"将地图保存到另外的目录中、复制/粘贴了不同文件夹地图的地块、或手手动添加了来自其他文件夹的地块表。
- 例如:
📁 Stardew Valley/ 📁 Content/ 📁 Maps/ 🗎 townInterior <──┐ 📁 Mods/ │ 📁 YourModName/ │ ../../../Content/Maps/townInterior 📁 assets/ │ 🗎 your-map.tmx ───┘
- 上述例子中的操作是不允许的,因为它非常脆弱(例如玩家可能将模组安装到不同的路径中)。
- 如何修复?
-
- 将您使用的地块表复制到地图所在的文件夹中。
- 对于您的地图中未经改动的原版地块表,在其前面加上点号(例如.townInterior.png)。这使SMAPI在加载地图时忽略此文件,并转而加载Content文件夹下的地块表。
- 在Tiled点击 Tilesets 面板下的 Edit Tileset 按钮。
- 在打开的页面中,点击 Tileset > Tileset Properties。
- 点击 Image 字段,然后点击 Edit 按钮以在相同文件夹下定位地块表。
Discord用户foggywizard#7430提供了上述3-5步的截图版教程。
- 修复完成后,上述例子应当如下所示:
📁 Stardew Valley/ 📁 Mods/ 📁 YourModName/ 📁 assets/ 🗎 your-map.tmx ───┐ 🗎 .townInterior.png <──┘ .townInterior.png
"mod reordered the original tilesheets"
- 这是什么意思?
- 参见地块表顺序以了解更多信息。
- 如何修复?
- 请确保原版的地块表顺序不变,并将新增的地块表添加
z_
前缀以确保其位于原版地块表后方。
- 在Tiled中重命名受影响的地块表:
"mod has no tilesheet with ID '<name>'"
- 这是什么意思?
- 您替换了某张原版地图,但是您的自定义地图并不具有原版地图全部的地块表(或您在Tiled中更改了这些地块表的名称)。当游戏试图使用缺失的地块表时,就会崩溃。
- 如何修复?
- 在Tiled中比对原版地图和自定义地图。对于原版地图中的每张地块表,都要确保自定义地图中有相同地块表且其名称不变(无论您是否使用了此地块表)。
- 若您需要重命名地块表:
- 在 Tileset 面板中,点击欲编辑的地块表选项卡,然后点击下方的 Edit Tileset 图标。
- 点击顶部菜单的 Tileset > Tileset Properties 以显示属性面板。
- 将 Name 字段重命名为原版地图的名称。
"Invalid tile GID: <#>"
- 这是什么意思?
- 在编辑地图时,有的地块表不与tmx文件位于同一文件夹,导致XML数据丢失关于此地块表的信息从而错误地重新计算了其他地块集的初始GID。
- 如何修复?
- 确保地图使用的所有地块表都与tmx文件位于同一文件夹,然后进行任意小修改,最后保存地图。
- 这应当能使Tiled更新XML数据并重新计算初始GID。然后您可以撤销您之间所作的修改,然后再次保存地图。
- 在编辑地图时,请务必确保您的地块集和tmx文件位于同一文件夹,以避免无效GID报错。
使用SMAPI作出更改
此页面主要讲述如何使用Tiled编辑地图,但是也可以使用C# SMAPI模组来进行同样的编辑。如下是使用C#代码修改地点的两个主要途径:
使用AssetRequested事件
多数地图编辑都应当通过AssetRequested事件来完成,因为这样做能防止其他模组重载地图造成您的修改丢失。在Map素材被游戏内地点加载前,AssetRequested事件即直接作用于Map素材;这意味着此处不能使用地点方法,但可以在地图被读取前作出任何所需修改(例如,更改传送点)。参见Events API以获得关于事件的帮助。
例如,下述模组代码编辑小镇地图,并添加一个可选的GetTile辅助方法:
/// <summary>The mod entry point.</summary>
internal sealed class ModEntry : Mod
{
/// <inheritdoc />
public override void Entry(IModHelper helper)
{
helper.Events.Content.AssetRequested += this.OnAssetRequested;
}
/// <inheritdoc cref="IContentEvents.AssetRequested"/>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event data.</param>
private void OnAssetRequested(object?/ sender, AssetRequestedEventArgs e)
{
if (e.Name.IsEquivalentTo("Maps/Town"))
{
e.Edit(asset =>
{
IAssetDataForMap editor = asset.AsMap();
Map map = editor.Data;
// your code here
});
}
}
/// <summary>Get a tile from the map.</summary>
/// <param name="map">The map instance.</param>
/// <param name="layerName">The name of the layer from which to get a tile.</param>
/// <param name="tileX">The X position measured in tiles.</param>
/// <param name="tileY">The Y position measured in tiles.</param>
/// <returns>Returns the tile if found, else <c>null</c>.</returns>
private Tile GetTile(Map map, string layerName, int tileX, int tileY)
{
Layer layer = map.GetLayer(layerName);
Location pixelPosition = new Location(tileX * Game1.tileSize, tileY * Game1.tileSize);
return layer.PickTile(pixelPosition, Game1.viewport.Size);
}
}
现在,您在地图被地点读取前对其作出任何更改。例如,您可以:
- 添加自定义地块表:
map.AddTileSheet(new TileSheet( id: "z_custom-tilesheet", // always prefix custom tilesheets with z_ to avoid reordering vanilla tilesheets map: map, imageSource: this.Helper.Content.GetActualAssetKey("assets/tilesheet.png", ContentSource.ModFolder), // get a unique asset name for local mod file which can be passed to the game sheetSize: new Size(32, 64), // the size in tiles for the tilesheet image tileSize: new Size(16) // the size of each tile in pixels, should always be 16 ));
- 管理地图属性:
// get a property value string currentMusic = map.Properties.TryGetValue("Music", out PropertyValue rawMusic) ? rawMusic.ToString() : null; // add/replace a property map.Properties["Music"] = "MarlonsTheme"; // delete a property map.Properties.Remove("Music");
- 管理地块属性:
// get tile Tile tile = this.GetTile(map, layerName: "Back", tileX: 10, tileY: 20); if (tile == null) return; // you should handle the tile not being there to avoid errors // get a property value string diggable = tile.TileIndexProperties.TryGetValue("Diggable", out PropertyValue rawDiggable) || tile.Properties.TryGetValue("Diggable", out rawDiggable) ? rawDiggable?.ToString() : null; // set a property tile.Properties["Diggable"] = "T"; // delete a property tile.Properties.Remove("Diggable");
- 添加新地块:
int tileX = 10; int tileY = 20; Layer layer = map.GetLayer("Back"); // add a static tile layer.Tiles[tileX, tileY] = new StaticTile( layer: layer, tileSheet: map.GetTileSheet("z_custom-tilesheet"), tileIndex: 100, // the sprite index in the tilesheet blendMode: BlendMode.Alpha // should usually be Alpha ); // add an animated tile layer.Tiles[tileX, tileY] = new AnimatedTile( layer: layer, tileFrames: new StaticTile[] { new StaticTile(...), new StaticTile(...), new StaticTile(...), }, frameInterval: 100 // frame duration in milliseconds );
- 删除地块:
layer.Tiles[tileX, tileY] = null;
- 应用地块变换:
Tile tile = this.GetTile(map, layerName: "Back", tileX, tileY); tile.Properties["@Rotation"] = 45; // rotate it 45° clockwise tile.Properties["@Flip"] = 1; // flip the tile: 0 (normal), 1 (horizontal), 2 (vertical)
另请参阅SMAPI的地图编辑助手,后者允许将自定义地图区域整合进地图等操作。
地点加载后
在游戏内地点加载完成后,您可以使用游戏的辅助方法以编辑地点及其地图。但需要注意:其他模组(包括游戏本身)随时可能更改地点,若不加以注意,则可能丢失所有更改。
例如,在任何游戏内事件中,可进行如下操作:
- 获取地图以使用上述方法:
Map map = location.map;
- 管理地块属性:
Town town = (Town)Game1.getLocationFromName("Town"); int tileX = 10; int tileY = 20; // get property value string diggable = town.doesTileHaveProperty(tileX, tileY, "Diggable", "Back"); // set property value location.setTileProperty(tileX, tileY, "Back", "Diggable", "T");
- 管理地块:
location.removeTile(tileX, tileY, "Back");
模组开发者帮助和技巧
- 您可以访问Stardew Valley Discord并在#Making Mods Section寻求帮助。
- Discord用户foggywizard#7430 制作了一些Tiled图解指南。包括图解概览、如何寻找坐标所在位置以及如何重命名地块表。
- 教程:Discord用户Draylon是如何绘制悬崖轮廓的。