模组:世界地图

来自Stardew Valley Wiki
跳到导航 跳到搜索

目录

此页面解释如何编辑世界地图。世界地图是指游戏菜单中显示的小地图,而不是游戏地点的地图数据。欲编辑后者,参见模组:地图。另请参阅创建模组

数据

概览

您可以通过编辑Data/WorldMap素材文件以编辑世界地图,包括但不限于:添加自定义地图、设置覆盖贴图、添加/编辑提示框、设置玩家图标等。

默认世界地图。地图对应星露谷地区,其中红框标记的部分是一个地图区域,它具有独立的贴图、提示框/名称、玩家图标定位。

关于世界地图有三个主要概念(对照右图):

  • 一个地区 (region) 是指世界的一大组成部分,它包含相应地图上的全部地点。例如,默认世界地图对应星露谷地区。
  • 一个地图区域 (map area) 是一张世界地图的子集,可以酌情添加提示框、滚动文本、贴图、玩家定位图标等内容。
  • 一个地图区域位置 (map area position) 对应于游戏内的地点以及地块坐标,以用于绘制地图。游戏使用地图区域位置来自动在世界地图上绘制玩家定位图标(定位图标适用于观察其他玩家在各个地点的行动等用途)。

在数据模型中:

  • 每个条目都是一个地区;
  • 每个条目的MapAreas为此地区的地图区域;
  • 每个地图区域的WorldPositions字段为相应地图区域位置。

游戏会首先查找与当前地点匹配的第一个WorldPositions条目,然后认为您正处于此地区和地图区域中。若未找到,则默认为农场。

格式

Data/WorldMap数据素材为一个“字符串 → 数据模型”查询,其中:

字段 效果
BaseTexture (可选) 为地图绘制的基础贴图(若有)。会应用第一个匹配的贴图。如果地图区域也提供了自己的贴图,则会绘制在基础贴图之上。

此字段为包含如下字段的数据模型所组成的列表:

字段 效果
Id 此列表项对应的唯一字符串ID
Texture 欲绘制贴图的素材名称。
SourceRect (可选) Texture中欲绘制的像素区域,为具有XYWidthHeight 字段的数据模型。默认为整张Texture图像。
MapPixelArea (可选) 地区中此区域应当覆盖的像素区域,为具有XYWidthHeight 字段的数据模型。若缺省,则自地图左上角开始绘制整张SourceRect
Condition (可选) 指示是否应当使用此贴图的游戏状态查询。默认为使用。
MapAreas 绘制在BaseTexture顶层的区域。可在此添加提示框、滚动文本、覆盖贴图和玩家定位信息。

此字段为包含如下字段的数据模型所组成的列表:

字段 效果
Id 列表中此地图区域的唯一字符串ID
PixelArea 该区域覆盖的地图像素区域。用于设置默认的玩家图标位置,也是下面其他字段中像素区域的默认值。
ScrollText (可选) 用于滚动文本的模板字符串(当玩家位于该区域时显示在地图底部)。默认为none。
Textures (可选) 应用于地图的覆盖贴图。会应用所有匹配贴图。

此字段为包含如下字段的数据模型所组成的列表:

字段 效果
Id 此贴图的唯一字符串ID
Texture 欲绘制的贴图的素材名称。如果设置为字符串 MOD_FARM,游戏将应用当前农场类型的贴图(无论它是原版还是模组农场类型)。通常应与 “MapPixelArea”: “0 43 131 61"</代码>一起使用(默认地图上的农场区域)。
SourceRect (可选)

要绘制的 Texture 中的像素区域,指定为包含 XYWidthHeight 字段的数据模型。默认为整张贴图。

MapPixelArea (可选) 该区域覆盖的地图像素区域,指定为一个包含 XYWidthHeight 字段的数据模型。若省略,默认为地图区域的 PixelArea
Condition (可选) 指示是否应当使用此贴图的游戏状态查询。默认为使用。
Tooltips (可选) 将鼠标悬停在世界地图上该地点时显示的提示框。

此字段为包含如下字段的数据模型所组成的列表:

字段 效果
Id 此区域的唯一字符串ID
Text (可选) 用作提示框文本的模板字符串
PixelArea (可选) 地图上可以悬停显示该提示框的像素区域。默认为该区域的 PixelArea
Condition (可选) 指示此提示框是否可用的游戏状态查询。默认为可用。
KnownCondition (可选) 指示此区域是否已知的游戏状态查询。若为未知区域,则提示框显示???。默认为已知。
LeftNeighbor
RightNeighbor
UpNeighbor
DownNeighbor
(可选) 当使用手柄浏览世界地图时,当玩家移动光标时,光标会吸附到的提示框。

必须以 areaId/tooltipId 的格式指定区域和提示框(不区分大小写)。如果有多个可能的Neighbor,可用逗号分隔;将使用第一个有效的Neighbor

下面的例子使得当用户向右移动光标时,将光标吸附到社区中心:

"RightNeighbor": "Town/CommunityCenter"

空值会被自动忽略,但如果指定的Neighbor ID 都不匹配,游戏会记录一个警告。要想静默忽略它们(例如,需要特殊条件才能进入的地点),可以添加ignore选项:

"RightNeighbor": "Town/SomeOptionalLocation, ignore"

另请参阅地区数据中的MapNeighborIdAliases字段

WorldPositions (可选) 地点和地块坐标要与该地图区域相匹配。游戏会以此自动将玩家图标绘制在世界地图上的相对位置(定位图标适用于观察其他玩家在各个地点的行动等用途)。

此字段为包含如下字段的数据模型所组成的列表:

字段 效果
Id 此地点的唯一字符串ID
LocationContext (可选) 此位置的地点上下文。原版上下文为Default(星露谷地区)和Island姜岛地区)。
LocationName (可选) 此位置的地点名称。任何位于矿井骷髅洞穴内的位置都将分别被命名为MinesSkullCave(即对应的地点名称),而节日则使用地图素材名称(例如 Town-EggFestival)。
LocationNames (可选) 相当于LocationName,但允许指定多个地点的数组。
TileArea
MapPixelArea
(可选) 地点内的地块区域(TileArea)和世界地图上的等效像素区域(MapPixelArea)。这些区域可用于计算角色或玩家在地图中的位置。例如,如果玩家在游戏中位于平铺区域的右上角,那么他们就会显示在世界地图的右上角。

两个字段都被指定为带有 XYWidthHeight 字段的数据模型。TileArea默认为整个地点,而MapPixelArea默认为地图区域的PixelArea

ScrollText (可选) 一个模板字符串,用于当玩家位于此位置时地图底部显示的滚动文本。默认为地图区域的 ScrollText (若有)。
Condition (可选) 指示是否应用此列表项的游戏状态查询。默认为应用。
ScrollTextZones (可选,专用) 使世界地图位置中的小区域拥有独立的滚动文本(如深山区域中的 “山” 与 “山湖”)。

此字段为包含如下字段的数据模型所组成的列表。

字段 效果
Id 此列表项的唯一字符串ID
TileArea 。请参阅父字段的详细信息。
ScrollText 当玩家在此区域内时,地图底部的滚动文字。支持模板字符串
ExtendedTileArea (可选,专用) 显示此滚动文字的地块区域。可指定 TileArea 以外的地块。ExtendedTileArea 必须完全包含 TileArea,因为在初始检测时不会再检查后者。

例如,假设我们有 ExtendedTileArea(较大的方框)和 TileArea(其内部较小的方框),而玩家位于 X 位置:

┌────────────────────┐
│    ┌────────┐      │
│ X  │        │      │
│    │        │      │
│    └────────┘      │
└────────────────────┘

在这种情况下,此列表项将被选中(因为玩家位于 ExtendedTileArea 内),其坐标将被移动到最近的 TileArea 位置:

┌────────────────────┐
│    ┌────────┐      │
│    │X       │      │
│    │        │      │
│    └────────┘      │
└────────────────────┘

主要用于地块区域和实际地图布局不同的复杂地点。大多数情况下可忽略。

CustomFields 此列表项的自定义字段
MapNeighborIdAliases (可选) 某些提示框ID的别名,可用于Tooltips下辖字段(如LeftNeighbor)。别名不能递归。

下面的代码会设置了Beach/FishShop_DefaultHoursBeach/FishShop_ExtendedHours的别名Beach/Fishshop。您可以直接在Neighbor字段中使用Beach/Fishshop,而不必每次都指定具体的提示框ID。

"MapNeighborIdAliases": {
    "Beach/FishShop": "Beach/FishShop_DefaultHours, Beach/FishShop_ExtendedHours"
}

示例

下面的Content Patcher内容包为姜岛添加了一个新的世界地图。如果玩家解锁了海滩度假村,则会应用海滩度假村贴图。

{
    "Format": "2.3.0",
    "Changes": [
        // add world map edits
        {
            "Action": "EditData",
            "Target": "Data/WorldMap",
            "Entries": {
                "GingerIsland": {
                    "BaseTexture": [
                        {
                            "Id": "Default",
                            "Texture": "{{InternalAssetKey: assets/ginger-island.png}}"
                        }
                    ],
                    "MapAreas": [
                        // the Island South (dock) area
                        {
                            // basic info for the area within the map
                            "Id": "IslandSouth",
                            "PixelArea": { "X": 105, "Y": 105, "Width": 231, "Height": 240 },
                            "ScrollText": "Dock", // example only, should usually be translated

                            // a tooltip shown when hovering over the area on the map
                            "Tooltips": [
                                {
                                    "Id": "Dock",
                                    "Text": "Dock" // example only, should usually be translated
                                }
                            ],

                            // if the resort is unlocked, overlay a custom texture on top of the default Ginger Island map
                            "Textures": [
                                {
                                    "Id": "Resort",
                                    "Texture": "{{InternalAssetKey: assets/resort.png}}",
                                    "Condition": "PLAYER_HAS_FLAG Any Island_Resort"
                                }
                            ],

                            // the in-game locations that are part of this world map area
                            "WorldPositions": [
                                {
                                    "LocationName": "IslandSouth"
                                }
                            ]
                        }
                    ]
                }
            }
        }
    ]
}

实时定位

世界地图一般会实时显示玩家的位置。对于自定义地点,主要有三种方法。

自动定位(推荐)

如果实际地点和游戏地图显示的地点较为契合,游戏可以根据 Data/WorldMap 中的 PixelAreaLocationName 字段自动确定位置。例如,位于游戏中位置正中心的玩家将被绘制在所绘制地图区域的中心。

为此

  1. 截一张此地点的完整图片
  2. Paint.NETGIMP等图片编辑器打开此截图。
  3. 按需裁切,然后将尺寸调整为地图上此地点的尺寸。确保您使用的是"nearest neighbor"算法[1]
  4. 酌情修改,以求美观。

这样就做好了!您可以将此图片作为该地点的世界地图贴图(存储在Data/WorldMap),这样游戏就可以自动在地图上定位玩家。当您使用此自动定位方式时,可以省略WorldPositions字段。

  1. 对于Paint. NET,将Rescale菜单中的Resampling选项设为Nearest Neighbor ;对于GIMP,将Interpolation设为None即可。

手动定位

如果地点的真实布局和地图上显示的有所出入,则可以在Data/WorldMap中使用WorldPositions字段来手动设置定位。这可能非常棘手,故不推荐。强烈推荐自动定位

例如,在《星露谷物语 1.6》之前,深山的地图区域非常不写实(矿井和探险家公会紧挨着,没有湖心岛,公会南面没有山湖,等等):

1.6版之前深山的真实样貌(上)和世界地图区域(下)

在手动定位时,您可以通过TileAreaMapPixelArea字段添加任意数量的世界位置。其中,TileArea是指玩家真实的地块坐标,而MapPixelArea是指地图上显示的位置。当玩家位于 TileArea 内时,他们将被映射到对应的 MapPixelArea 内的相对位置。例如,如果玩家位于 TileArea 的正中心,那么他们将被绘制在 MapPixelArea 的中心。


参见下面的例子,您可以像这样将 1.6 之前的深山划分为多个区域(有关每个字段的信息,请参阅数据格式):

"WorldPositions": [
    {
        "Id": "Quarry",
        "LocationName": "Mountain",
        "TileArea": { "X": 95, "Y": 11, "Width": 36, "Height": 24 },
        "ExtendedTileArea": { "X": 95, "Y": 0, "Width": 255, "Height": 255 },
        "MapPixelArea": { "X": 236, "Y": 29, "Width": 28, "Height": 19 }
    },
    {
        "Id": "Lake_Guild",
        "LocationName": "Mountain",
        "TileArea": { "X": 73, "Y": 5, "Width": 22, "Height": 30 },
        "ExtendedTileArea": { "X": 73, "Y": 0, "Width": 22, "Height": 255 },
        "MapPixelArea": { "X": 227, "Y": 29, "Width": 9, "Height": 19 }
    },
    {
        "Id": "Lake_BetweenGuildAndMine",
        "LocationName": "Mountain",
        "TileArea": { "X": 57, "Y": 5, "Width": 16, "Height": 32 },
        "ExtendedTileArea": { "X": 57, "Y": 0, "Width": 16, "Height": 255 },
        "MapPixelArea": { "X": 224, "Y": 29, "Width": 3, "Height": 19 }
    },
    {
        "Id": "Lake_Mine",
        "LocationName": "Mountain",
        "TileArea": { "X": 52, "Y": 5, "Width": 5, "Height": 30 },
        "ExtendedTileArea": { "X": 52, "Y": 0, "Width": 5, "Height": 255 },
        "MapPixelArea": { "X": 220, "Y": 29, "Width": 4, "Height": 19 }
    },
    {
        "Id": "Lake_MineBridge",
        "LocationName": "Mountain",
        "TileArea": { "X": 44, "Y": 5, "Width": 8, "Height": 30 },
        "ExtendedTileArea": { "X": 44, "Y": 0, "Width": 8, "Height": 255 },
        "MapPixelArea": { "X": 210, "Y": 29, "Width": 10, "Height": 19 }
    },
    {
        "Id": "West",
        "LocationName": "Mountain",
        "TileArea": { "X": 0, "Y": 5, "Width": 44, "Height": 30 },
        "ExtendedTileArea": { "X": 0, "Y": 0, "Width": 44, "Height": 255 },
        "MapPixelArea": { "X": 175, "Y": 29, "Width": 35, "Height": 19 }
    },
    {
        "Id": "Default",
        "LocationName": "Mountain"
    }
]

下面是这些区域的直观示意图:

早于1.6版本的深山真实样貌,TileArea位置(顶部、高亮)和MapPixelArea位置(底部、高亮)。

请注意,矿井和冒险者公会之间的区域实际上很宽,但在绘制的世界地图上却很窄。当玩家走过这部分区域时,他们的图标将在地图上缓慢地走过相应区域。

如果玩家在 TileArea 之外,但在 ExtendedTileArea(如果已设置)之内,他们的位置将被调整到 TileArea 内最近的位置。例如,请注意木匠店南面位置的底部并不属于红色区域。但它该区域的ExtendedTileArea的一部分,因此在那里的玩家将被定位到世界地图上红色区域的底部。

固定位置

对于非常复杂的地点,可能无法在世界地图上实时定位(例如,因为绘制的世界地图非常不写实)。在这种情况下,您可以在世界地图上设置一个固定位置(或多个固定位置)。

请看下面的例子。它会根据玩家在镇上的真实位置,在世界地图的五个固定位置之一绘制玩家图标。TileArea指示玩家真实的地块坐标,而MapPixelArea则是在地图上绘制玩家图标的位置。请注意,在下面的代码中,后者始终是 1x1 像素,这意味着 TileArea 内的任何位置都对应世界地图上的同一个像素。最后一项没有 TileArea,这意味着它适用于所有与前一项不匹配的位置。

"WorldPositions": [
    {
        "Id": "East_NearJojaMart",
        "LocationName": "Town",
        "TileArea": { "X": 85, "Y": 0, "Width": 255, "Height": 68 },
        "MapPixelArea": { "X": 225, "Y": 81, "Width": 1, "Height": 1 }
    },
    {
        "Id": "East_NearMuseum",
        "LocationName": "Town",
        "TileArea": { "X": 81, "Y": 68, "Width": 255, "Height": 255 },
        "MapPixelArea": { "X": 220, "Y": 108, "Width": 1, "Height": 1 }
    },
    {
        "Id": "West_North",
        "LocationName": "Town",
        "TileArea": { "X": 0, "Y": 0, "Width": 85, "Height": 43 },
        "MapPixelArea": { "X": 178, "Y": 64, "Width": 1, "Height": 1 }
    },
    {
        "Id": "West_Center",
        "LocationName": "Town",
        "TileArea": { "X": 0, "Y": 43, "Width": 85, "Height": 33 },
        "MapPixelArea": { "X": 175, "Y": 88, "Width": 1, "Height": 1 }
    },
    {
        "Id": "West_South",
        "LocationName": "Town",
        "MapPixelArea": { "X": 182, "Y": 109, "Width": 0, "Height": 0 }
    }
]

在C#中与世界地图交互

SMAPI模组(使用C#)可以调用游戏的StardewValley.WorldMaps.WorldMapManager类以与世界地图互动。

例如,您可以获取某地块坐标在世界地图上对应的像素位置:

MapAreaPosition mapAreaPosition = WorldMapManager.GetPositionData(location, tile);
if (mapAreaPosition != null)
    return mapAreaPosition.GetMapPixelPosition(location, tile);

调试视图

您可以在 SMAPI 控制台窗口中运行 debug worldMapLines,以启用世界地图的调试视图。这将勾勒出地图区域(黑色)、地图区域位置(蓝色)和提示框(绿色):

调试视图下的世界地图

您也可以自行指定要框起来的地图元素,例如debug worldMapLines areas positions tooltips