Модификации:Основные возможности: различия между версиями

Материал из Stardew Valley Wiki
Перейти к навигации Перейти к поиску
м (Замена текста — «{{quote|» на «{{Quote|»)
 
(не показано 12 промежуточных версий 3 участников)
Строка 1: Строка 1:
← [[Модификации]]
+
← [[Модификации:Индекс]]
{{stub}}
 
  
 
В этой статье описываются основные возможности SMAPI. '''Перед прочтением данной статьи, рекомендуется прочитать [[Modding:Modder Guide|Modder Guide]] и [[Modding:Modder Guide/Game Fundamentals|Game Fundamentals]].'''
 
В этой статье описываются основные возможности SMAPI. '''Перед прочтением данной статьи, рекомендуется прочитать [[Modding:Modder Guide|Modder Guide]] и [[Modding:Modder Guide/Game Fundamentals|Game Fundamentals]].'''
Строка 6: Строка 5:
 
==Основы==
 
==Основы==
 
===Отслеживание изменений переменной===
 
===Отслеживание изменений переменной===
Модам часто приходится отслеживать изменение какого-либо значения. Если для значения в SMAPI нет события, можно создать [https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/fields приватное поле] для отслеживания значения, и обновлять его, используя событие обновления. Например, вот полностью работающий мод, который выводит сообщение в консоль, когда выносливость игрока изменяется:
+
Модам часто приходится отслеживать изменение какого-либо значения. Если для параметра в SMAPI нет события, можно создать [https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/classes-and-structs/fields приватное поле], и обновлять его, используя событие обновления. Например, вот полностью работающий мод, который выводит сообщение в консоль, когда выносливость игрока изменяется:
  
 
<source lang="c#">
 
<source lang="c#">
Строка 64: Строка 63:
  
 
==Предметы==  
 
==Предметы==  
Предметы - это объекты, которые могут быть помещены в инвентарь. Инструменты, культуры и т.п.
+
Предметы - это объекты, которые могут быть помещены в инвентарь. Предметами являются инструменты, семена, урожай и т.п.
  
 
===Создание предмета (Объекта)===
 
===Создание предмета (Объекта)===
Строка 78: Строка 77:
 
Где '''parentSheetIndex''' это ID предмета (может быть найдено в ObjectInformation.xnb).
 
Где '''parentSheetIndex''' это ID предмета (может быть найдено в ObjectInformation.xnb).
  
===Создание предмета на поверхности===
+
===Создание предмета на клетке===
  
 
<source lang='c#'>
 
<source lang='c#'>
Строка 96: Строка 95:
 
Чтобы удалить предмет в большинстве ситуаций необходимо просто вызвать метод .removeItemFromInventory(Item)
 
Чтобы удалить предмет в большинстве ситуаций необходимо просто вызвать метод .removeItemFromInventory(Item)
  
==Locations==
+
==Локации==
The ''GameLocation'' is a representation of any place in the game (e.g. Farm, Town)
+
''Игровой локацией'' является любое место в игре (Ферма, Город, Шахта)
  
The list of current locations is stored in ''Game1.currentLocations''
+
''Game1.currentLocation'' является ссылкой на текущую локацию в которой находится игрок.
  
'''Important Caveat''': In 1.3 onwards, the ''Game1.currentLocations'' is not reliable for farmhands in MP.
+
'''Важное предупреждение''': Начиная с версии 1.3 ''Game1.currentLocation'' использовать в мультиплеере не рекомендуется.
  
===Map Properties===
+
===Свойства карты===
You can edit many properties of the current map and the tiles in the map. This is already documented here [[Modding:Maps#Map_properties | Map Properties]]
+
Многие свойства карты, а также клеток на ней можно изменить. Для детальной информации читайте [[Модификации:Карты#Свойства карты|свойства карты]]
  
===Tiles===
+
===Обработка клетки===
''terrainFeatures'' contains information about the tiles. (e.g. dirt, grass, crops, etc.)
+
Поле ''.terrainFeatures'' содержит свойство .Pairs, которое используется для получения доступа к элементу набора клеток (земля, трава, грядка).  
 
 
''objects'' contains information about objects on top of tiles. (e.g. crops, stones)
 
 
 
===Handling TerrainFeatures===
 
 
 
As ''terrainFeatures'' is a NetField, always use .Pairs to access it for enumeration. The .Key value of this stores the location, and the .Value contains the terrainFeature itself.  As a note, this includes items spawned off the map, which is usually cleared at end of day.  
 
 
 
If you need to access just crops, this snippet will be of use:
 
  
 +
Ниже приведен фрагмент для обработки клетки с [[Культуры|культурой]]:
 
<source lang="c#">
 
<source lang="c#">
  
Строка 128: Строка 120:
 
</source>
 
</source>
  
If you need some other location, sub that out for Game1.getFarm(). Note this doesn't null check Farm! Make sure Farm is loaded.
+
Для указания другой локации необходимо заменить Game1.getFarm(). Обратите внимание: в примере не производится проверка локации на существование (null check)!
 +
 
 +
===Обработка объектов на клетке===
 +
Для обработки объектов есть несколько полей, но чаще всего используется ''.objects''. В нем содержится информация об объектах (семена, камень, древесина).
 +
 
 +
Действия аналогичны TerrainFeatures, за исключением того, что нельзя размещать объекты за пределами карты.
  
===Handling Objects===
+
==Игрок==
  
There are several fields that handle objects, but always use the .objects one. The same rules apply as in TerrainFeatures, except that you really can't place objects beyond the edge of the map.
+
===Местоположение===
 +
Позиция персонажа указывает координаты персонажа в текущей локации.
  
==Player==
+
====Позиция игрока в локации====
//todo describe section
+
Каждая локация представлена ''xTile'' картой, где левый верхний угол имеет координаты ''(0, 0)'', а правый нижний - ''(location.Map.DisplayWidth, location.Map.DisplayHeight)'' пикселей.  
===Position===
 
A Character's position indicates the Character's coordinates in the current location.  
 
  
====Position Relative to the Map====
+
Существуют два способа узнать текущее местоположение персонажа в локации: по абсолютной позиции или по координатам клетки.
Each location has an ``xTile`` map where the top-left corner of the map is ''(0, 0)'' and the bottom-right corner of the map is ''(location.Map.DisplayWidth, location.Map.DisplayHeight)'' in pixels.  
 
  
There are two ways to get a Character's position in the current location: by absolute position and by tile position.
+
<code>Position.X</code> и <code>Position.Y</code> вернут координаты XY в пикселях.
  
<code>Position.X</code> and <code>Position.Y</code> will give the XY coordinates in pixels.
+
<code>getTileX()</code> и <code>getTileY()</code> вернут координаты XY клетки в сетке тайл-листа.
  
<code>getTileX()</code> and <code>getTileY()</code> will give the XY coordinates in tiles.
+
Согласно <code>Game1.tileSize</code> клетка имеет размер 64x64  пикселей, что дает возможность конвертировать абсолютную и относительную позиции:
  
Each tile is 64x64 pixels as specified by <code>Game1.tileSize</code>. The conversion between absolute and tile is as follows:
 
 
<source lang='c#'>
 
<source lang='c#'>
// Absolute position => Tile position
+
// Абсолютная позиция => Позиция клетки
 
Math.Floor(Game1.player.Position.X / Game1.tileSize)
 
Math.Floor(Game1.player.Position.X / Game1.tileSize)
 
Math.Floor(Game1.player.Position.Y / Game1.tileSize)
 
Math.Floor(Game1.player.Position.Y / Game1.tileSize)
  
// Tile position => Absolute position
+
// Позиция клетки => Абсолютная позиция
 
Game1.player.getTileX() * Game1.tileSize
 
Game1.player.getTileX() * Game1.tileSize
 
Game1.player.getTileY() * Game1.tileSize
 
Game1.player.getTileY() * Game1.tileSize
  
// Tilemap dimensions
+
// Размеры клетки
 
Math.Floor(Game1.player.currentLocation.Map.DisplayWidth / Game1.tileSize)
 
Math.Floor(Game1.player.currentLocation.Map.DisplayWidth / Game1.tileSize)
 
Math.Floor(Game1.player.currentLocation.Map.DisplayHeight / Game1.tileSize)
 
Math.Floor(Game1.player.currentLocation.Map.DisplayHeight / Game1.tileSize)
 
</source>
 
</source>
  
====Position Relative to the Viewport====
+
====Позиция игрока в видимой области====
The viewport represents the visible area on the screen. Its dimensions are <code>Game1.viewport.Width</code> by <code>Game1.viewport.Height</code> in pixels; this is the same as the game's screen resolution.
+
Размеры видимой области экрана можно узнать используя <code>Game1.viewport.Width</code> и <code>Game1.viewport.Height</code>. Размеры указаны в пикселях и соответствуют разрешению экрана игры.
 
+
The viewport also has an absolute position relative to the map, where the top-left corner of the viewport is at ''(Game1.viewport.X, Game1.viewport.Y)''.  
+
Также видимая область имеет абсолютную позицию относительно карты, где левый верхний угол находится в ''(Game1.viewport.X, Game1.viewport.Y)''.
  
 
+
Позиция игрока относительно видимой области вычисляется следующим образом:
The player's position in pixels relative to the viewport is as follows:
 
 
<source lang='c#'>
 
<source lang='c#'>
 
Game1.player.Position.X - Game1.viewport.X
 
Game1.player.Position.X - Game1.viewport.X
Строка 175: Строка 168:
 
</source>
 
</source>
  
==NPC==
+
==Неигровые персонажи==
===Creating Custom NPCs===
+
===Создание пользовательского НИПа===
Adding new NPCs involves editing a number of files:
+
Добавление нового НИПа включает в себя редактирование нескольких файлов:
  
* New file: Characters\Dialogue\<name>
+
* Создание файла: Characters\Dialogue\<имя>
* New file: Characters\schedules\<name>
+
* Создание файла: Characters\schedules\<имя>
* New file: Portraits\<name>
+
* Создание файла: Portraits\<имя>
* New file: Characters\<name>
+
* Создание файла: Characters\<имя>
* Add entries Data\EngagementDialogue for NPCs that are marriable
+
* Добавление записей Data\EngagementDialogue для НИПов, с которыми можно заключить брак
* Add entry to Data\NPCDispositions
+
* Добавление записи в Data\NPCDispositions
* Add entry to Data\NPCGiftTastes
+
* Добавление записи в Data\NPCGiftTastes
* Add entries to Characters\Dialogue\rainy
+
* Добавление записей в Characters\Dialogue\rainy
* Add entries to Data\animationDescriptions (if you want custom animations in their schedule)
+
* Добавление записей в Data\animationDescriptions (если нужны пользовательские анимации в расписании)
  
All of the above can be done with IAssetLoaders/IAssetEditors or Content Patcher. Finally, spawn the NPC with a SMAPI mod. The different constructors are:
+
Все это можно сделать с помощью IAssetLoaders/IAssetEditors или Content Patcher. В завершении, создается НИП, используя конструкторы SMAPI:
  
 
<source lang='c#'>
 
<source lang='c#'>
Строка 197: Строка 190:
 
</source>
 
</source>
  
For spawning:
+
Для спавна:
  
 
<source lang='c#'>
 
<source lang='c#'>
Строка 203: Строка 196:
 
</source>
 
</source>
  
==UI==
+
==Пользовательский интерфейс==
  
The UI is a collection of separate elements which make up the HUD and occasional popups.
+
Пользовательский интерфейс представляет собой набор отдельных элементов, которые составляют [https://ru.wikipedia.org/wiki/Head-Up_Display_(игры) HUD] и всплывающие окна.
  
//todo expand section.
+
//необходимо дополнить раздел.
  
  
===Banner Message===
+
===Всплывающие сообщения===
HUDMessage are those popups in the lower left hand screen. They have several constructors, which we will briefly go over here (a few non relevant ones have been snipped):
+
HUDMessage - это всплывающие сообщения в нижнем левом углу экрана. У них есть несколько конструкторов, которые указаны ниже (несколько не релевантных были пропущены):
  
 
<source lang="c#">
 
<source lang="c#">
Строка 222: Строка 215:
  
  
So before we go over when you'd use them, I'm going to briefly note how the class HUDMessage uses these. (I encourage people to read the class if they have further questions, but I doubt most of us will need to know more than this)
+
Ниже даны описания основных аргументов, которые требуются для создания сообщения. (Для полного описания рекомендуется читать информацию о классе, но в большинстве ситуации информации ниже достаточно)
 
 
  
 
WhatType:
 
WhatType:
*1 - Achievement
+
*1 - Достижение
*2 - New Quest
+
*2 - Новый квест
*3 - Error
+
*3 - Ошибка
*4 - Stamina
+
*4 - Выносливость
*5 - Health
+
*5 - Здоровье
 
 
  
Color: Fairly obvious. It should be noted that while the first two don't give an option (they default to ''Color:OrangeRed''), the fourth with the param 'leaveMeNull' displays as the same color as the game text.
 
  
 +
Color:  Цвет. В первых двух конструкторах используется цвет по умолчанию (''Color:OrangeRed''), а в четвертом - параметр 'leaveMeNull' отображается тем же цветом, что и текст игры.
  
For specifics:
 
*'' public HUDMessage(string type, int number, bool add, Color color, Item messageSubject = null);'' - This allows for expanded customization of the message. More often used for money.
 
*''  public HUDMessage(string message, string leaveMeNull)'' - Also displays no icon.
 
*''  public HUDMessage(string message, Color color, float timeLeft, bool fadeIn)'' - Displays a message that fades in for a set amount of time.
 
  
 +
Для примера:
 +
*'' public HUDMessage(string type, int number, bool add, Color color, Item messageSubject = null);'' - Подходит для кастомизации сообщения. Чаще всего используется для денег.
 +
*'' public HUDMessage(string message, string leaveMeNull)'' - Сообщение без иконки.
 +
*'' public HUDMessage(string message, Color color, float timeLeft, bool fadeIn)'' - Выводит сообщение, которое исчезает в течении установленного времени.
  
Note: For those of you who want a custom HUDMessage:
 
- Almost all of these variables are public, excluding messageSubject, so feel free to customize!
 
  
 +
Примечание:
 +
- Все переменные являются публичными, кроме messageSubject, поэтому не стесняйтесь кастомизировать!
  
  
For example: add a new HUDMessage to show [insert image] toaster popup.
+
Пример: Всплывающее сообщение об [[Файл:error-image-ingame.png]] ошибке:
 
<source lang="c#">
 
<source lang="c#">
 
Game1.addHUDMessage(new HUDMessage("MESSAGE", 3));
 
Game1.addHUDMessage(new HUDMessage("MESSAGE", 3));
 
</source>
 
</source>
  
==Menus==
+
==Меню==
//todo describe section
+
//добавить описание раздела
===Get the Active Menu===
+
 
You can use ''Reflection'' to get the current active menu in ''GameMenu''. The ''GameMenu'' contains the Inventory, Skills, Social, Map, Crafting, Collections, and Options pages in this respective order, accessed by the tab index with ''inventoryTab'' at 0.
+
===Получение информации о активной вкладки меню===
 +
Используйте ''Reflection'', чтобы узнать какая вкладка ''GameMenu'' сейчас активна. ''GameMenu'' содержит вкладки Инвентарь, Навыки, Светское, Карта, Изготовление предметов, Коллекции, и Настройки в указанном порядке. То есть вкладка ''inventoryTab'' имеет индекс 0.
  
 
<source lang="c#">
 
<source lang="c#">
Строка 262: Строка 254:
 
   IClickableMenu page = pages[menu.currentTab];
 
   IClickableMenu page = pages[menu.currentTab];
  
   // Example for getting the MapPage
+
   // Получение вкладки Карта
 
   MapPage mapPage = (MapPage) pages[menu.currentTab];
 
   MapPage mapPage = (MapPage) pages[menu.currentTab];
  
   // Two examples of checking if MapPage is open
+
   // Два примера проверки, что вкладка Карта открыта
 
   pages[menu.currentTab] is MapPage || menu.currentTab == GameMenu.mapTab;
 
   pages[menu.currentTab] is MapPage || menu.currentTab == GameMenu.mapTab;
 
}
 
}
 
</source>
 
</source>
  
===Set the Active Menu===
+
===Установка активной вкладки меню===
 
Game1.activeClickableMenu = <Menu>
 
Game1.activeClickableMenu = <Menu>
===Simple Menu===
 
Copy the menu you want from the game and make it your own
 
  
 
==Harmony==
 
==Harmony==
{{quote|Here be dragons. Thou art forewarned.}}
+
{{Quote|Here be dragons. Thou art forewarned.}}
  
[https://github.com/pardeike/Harmony Harmony] lets you patch Stardew Valley methods directly. This is very powerful, but comes with major caveats:
+
[https://github.com/pardeike/Harmony Harmony] позволяет напрямую использовать методы игры. Это очень мощный инструмент, но есть серьезные оговорки:
  
* It's very easy to cause crashes, errors, or subtle bugs.
+
* Очень легко вызвать сбои, ошибки или неотлавливаемые баги.
* It may cause difficult-to-diagnose memory corruption errors.
+
* Это может привести к затруднению диагностики ошибок повреждения памяти.
* Crossplatform compatibility is not guaranteed, and should be tested on all three platforms.
+
* Кроссплатформенная совместимость не гарантируется и должна быть протестирована на всех трех платформах.
* May conflict with other Harmony mods (e.g. if two mods patch the same method, or two mods try to load different versions of Harmony).
+
* Может конфликтовать с другими модами Harmony (например, если два мода используют один и тот же метод, или два мода пытаются загрузить разные версии Harmony).
* Harmony patch errors may have unpredictable effects on other mods that aren't using Harmony.
+
* Патчи Harmony могут иметь непредсказуемые эффекты для других модов, которые не используют Harmony.
  
Using Harmony should be a last resort, and is deliberately not documented.
+
Использование Harmony должно быть последним средством, и поэтому намеренно не документировано.
  
==Other==
+
==Другое==
===Add a small animation===
+
===Добавление небольшой анимации===
 
<source lang="c#">
 
<source lang="c#">
 
location.temporarySprites.Add(new TemporaryAnimatedSprite(...))
 
location.temporarySprites.Add(new TemporaryAnimatedSprite(...))
 
</source>
 
</source>
See ''TemporaryAnimatedSprite'' for more details
+
Смотрите ''TemporaryAnimatedSprite'' для детальной информации
  
===Play a sound===
+
===Воспроизведение звука===
 
<source lang="c#">
 
<source lang="c#">
 
location.playSound("SOUND");  
 
location.playSound("SOUND");  
 
</source>
 
</source>
(e.g. "junimoMeep1")
+
(''e.g.,'' "junimoMeep1")
  
===Send a letter===
+
===Отправка письма===
  
Use IAssetEditor to inject new mail into Data\Mail.xnb. Then use Game1.addMailForTomorrow to send it to the player.
+
Используйте IAssetEditor, чтобы добавить новое письмо в Data\Mail.xnb. Затем вызывайте метод Game1.addMailForTomorrow, чтобы отправить его игроку.
  
 
<source lang="c#">
 
<source lang="c#">
Строка 309: Строка 299:
 
</source>
 
</source>
  
Where mailName is the letter key in Mail.xnb. If you use the string '''wizard''' anywhere in the letter key, the letter will have the Wizard's new background (since 1.3) automatically.
+
Где mailName ключ в Mail.xnb. Если использовать строку '''wizard''' где угодно в ключе, то письмо будет иметь волшебный фон[?] (начиная с 1.3) автоматически.
 
 
==Open source==
 
When all else fails, when you've looked at the decompiled source too long and it makes no sense, take a look at some open-source mod code! See the 'source' column in the [[Modding:SMAPI compatibility|mod compatibility list]] for source code.
 
  
[[Category:Modding]]
+
==Исходные коды==
 +
Если что-то не получается, в большинстве случаев есть возможность подсмотреть реализацию в исходном коде другого мода. Смотрите столбец 'Исходный коды' в [[Modding:SMAPI compatibility|списке совместимых модификаций]].
 +
[[Category:Модификации]]
  
 
[[en:Modding:Common tasks]]
 
[[en:Modding:Common tasks]]
 +
[[zh:模组:常用方法]]

Текущая версия на 07:26, 19 апреля 2023

Модификации:Индекс

В этой статье описываются основные возможности SMAPI. Перед прочтением данной статьи, рекомендуется прочитать Modder Guide и Game Fundamentals.

Основы

Отслеживание изменений переменной

Модам часто приходится отслеживать изменение какого-либо значения. Если для параметра в SMAPI нет события, можно создать приватное поле, и обновлять его, используя событие обновления. Например, вот полностью работающий мод, который выводит сообщение в консоль, когда выносливость игрока изменяется:

/// <summary>Входная точка мода.</summary>
internal class ModEntry : Mod
{
    /*********
    ** Свойства
    *********/
    /// <summary>Последнее значение выносливости игрока.</summary>
    private float LastStamina;


    /*********
    ** Публичные методы
    *********/
    /// <summary>При первой загрузке мода вызывается метод Entry</summary>
    /// <param name="helper">Provides simplified APIs for writing mods.</param>
    public override void Entry(IModHelper helper)
    {
        SaveEvents.AfterLoad += this.SaveEvents_AfterLoad;
        GameEvents.UpdateTick += this.GameEvents_UpdateTick;
    }


    /*********
    ** Приватные методы
    *********/
    /// <summary>Метод вызываемый при загрузке сохранения.</summary>
    /// <param name="sender">The event sender.</param>
    /// <param name="e">The event arguments.</param>
    private void SaveEvents_AfterLoad(object sender, EventArgs e)
    {
        this.LastStamina = Game1.player.Stamina;
    }

    /// <summary>Метод вызывается после события обновления (около 60 раз в секунду).</summary>
    /// <param name="sender">The event sender.</param>
    /// <param name="e">The event arguments.</param>
    private void GameEvents_UpdateTick(object sender, EventArgs e)
    {
        // выходим, если сохранение еще не загружено
        if (!Context.IsWorldReady)
            return;

        // выходим, если значение выносливости не изменилось
        float currentStamina = Game1.player.Stamina;
        if (currentStamina == this.LastStamina)
            return;

        // выводим сообщение и обновляем значение свойства LastStamina 
        this.Monitor.Log($"Player stamina changed from {currentStamina} to {this.LastStamina}");
        this.LastStamina = currentStamina;
    }
}

Предметы

Предметы - это объекты, которые могут быть помещены в инвентарь. Предметами являются инструменты, семена, урожай и т.п.

Создание предмета (Объекта)

Конструкторы класса для создания предмета:

 public Object(Vector2 tileLocation, int parentSheetIndex, int initialStack);
 public Object(Vector2 tileLocation, int parentSheetIndex, bool isRecipe = false);
 public Object(int parentSheetIndex, int initialStack, bool isRecipe = false, int price = -1, int quality = 0);
 public Object(Vector2 tileLocation, int parentSheetIndex, string Givenname, bool canBeSetDown, bool canBeGrabbed, bool isHoedirt, bool isSpawnedObject);

Где parentSheetIndex это ID предмета (может быть найдено в ObjectInformation.xnb).

Создание предмета на клетке

 public virtual bool dropObject(Object obj, Vector2 dropLocation, xTile.Dimensions.Rectangle viewport, bool initialPlacement, Farmer who = null);

 // Спавн предмета в локации:
 Game1.getLocationFromName("Farm").dropObject(new StardewValley.Object(itemId, 1, false, -1, 0), new Vector2(x, y) * 64f, Game1.viewport, true, (Farmer)null);

Добавление предмета в инвентарь

//todo

Удаление предмета из инвентаря

Удаление зависит от инвентаря. Чаще всего вызывается метод класса Player, расположенного в пространстве имен Farmer.

Чтобы удалить предмет в большинстве ситуаций необходимо просто вызвать метод .removeItemFromInventory(Item)

Локации

Игровой локацией является любое место в игре (Ферма, Город, Шахта)

Game1.currentLocation является ссылкой на текущую локацию в которой находится игрок.

Важное предупреждение: Начиная с версии 1.3 Game1.currentLocation использовать в мультиплеере не рекомендуется.

Свойства карты

Многие свойства карты, а также клеток на ней можно изменить. Для детальной информации читайте свойства карты

Обработка клетки

Поле .terrainFeatures содержит свойство .Pairs, которое используется для получения доступа к элементу набора клеток (земля, трава, грядка).

Ниже приведен фрагмент для обработки клетки с культурой:

foreach (var tf in Game1.getFarm().terrainFeatures.Pairs)
{
    if ((tf.Value is HoeDirt hd) && hd.crop != null)
    {
        // do crop like things here.
    }
}

Для указания другой локации необходимо заменить Game1.getFarm(). Обратите внимание: в примере не производится проверка локации на существование (null check)!

Обработка объектов на клетке

Для обработки объектов есть несколько полей, но чаще всего используется .objects. В нем содержится информация об объектах (семена, камень, древесина).

Действия аналогичны TerrainFeatures, за исключением того, что нельзя размещать объекты за пределами карты.

Игрок

Местоположение

Позиция персонажа указывает координаты персонажа в текущей локации.

Позиция игрока в локации

Каждая локация представлена xTile картой, где левый верхний угол имеет координаты (0, 0), а правый нижний - (location.Map.DisplayWidth, location.Map.DisplayHeight) пикселей.

Существуют два способа узнать текущее местоположение персонажа в локации: по абсолютной позиции или по координатам клетки.

Position.X и Position.Y вернут координаты XY в пикселях.

getTileX() и getTileY() вернут координаты XY клетки в сетке тайл-листа.

Согласно Game1.tileSize клетка имеет размер 64x64 пикселей, что дает возможность конвертировать абсолютную и относительную позиции:

// Абсолютная позиция => Позиция клетки
Math.Floor(Game1.player.Position.X / Game1.tileSize)
Math.Floor(Game1.player.Position.Y / Game1.tileSize)

// Позиция клетки => Абсолютная позиция
Game1.player.getTileX() * Game1.tileSize
Game1.player.getTileY() * Game1.tileSize

// Размеры клетки
Math.Floor(Game1.player.currentLocation.Map.DisplayWidth / Game1.tileSize)
Math.Floor(Game1.player.currentLocation.Map.DisplayHeight / Game1.tileSize)

Позиция игрока в видимой области

Размеры видимой области экрана можно узнать используя Game1.viewport.Width и Game1.viewport.Height. Размеры указаны в пикселях и соответствуют разрешению экрана игры.

Также видимая область имеет абсолютную позицию относительно карты, где левый верхний угол находится в (Game1.viewport.X, Game1.viewport.Y).

Позиция игрока относительно видимой области вычисляется следующим образом:

Game1.player.Position.X - Game1.viewport.X
Game1.player.Position.Y - Game1.viewport.Y

Неигровые персонажи

Создание пользовательского НИПа

Добавление нового НИПа включает в себя редактирование нескольких файлов:

  • Создание файла: Characters\Dialogue\<имя>
  • Создание файла: Characters\schedules\<имя>
  • Создание файла: Portraits\<имя>
  • Создание файла: Characters\<имя>
  • Добавление записей Data\EngagementDialogue для НИПов, с которыми можно заключить брак
  • Добавление записи в Data\NPCDispositions
  • Добавление записи в Data\NPCGiftTastes
  • Добавление записей в Characters\Dialogue\rainy
  • Добавление записей в Data\animationDescriptions (если нужны пользовательские анимации в расписании)

Все это можно сделать с помощью IAssetLoaders/IAssetEditors или Content Patcher. В завершении, создается НИП, используя конструкторы SMAPI:

 public NPC(AnimatedSprite sprite, Vector2 position, int facingDir, string name, LocalizedContentManager content = null);
 public NPC(AnimatedSprite sprite, Vector2 position, string defaultMap, int facingDir, string name, Dictionary<int, int[]> schedule, Texture2D portrait, bool eventActor);
 public NPC(AnimatedSprite sprite, Vector2 position, string defaultMap, int facingDirection, string name, bool datable, Dictionary<int, int[]> schedule, Texture2D portrait);

Для спавна:

 Game1.getLocationFromName("Town").addCharacter(npc);

Пользовательский интерфейс

Пользовательский интерфейс представляет собой набор отдельных элементов, которые составляют HUD и всплывающие окна.

//необходимо дополнить раздел.


Всплывающие сообщения

HUDMessage - это всплывающие сообщения в нижнем левом углу экрана. У них есть несколько конструкторов, которые указаны ниже (несколько не релевантных были пропущены):

  public HUDMessage(string message);
  public HUDMessage(string message, int whatType);
  public HUDMessage(string type, int number, bool add, Color color, Item messageSubject = null);
  public HUDMessage(string message, string leaveMeNull)
  public HUDMessage(string message, Color color, float timeLeft, bool fadeIn)


Ниже даны описания основных аргументов, которые требуются для создания сообщения. (Для полного описания рекомендуется читать информацию о классе, но в большинстве ситуации информации ниже достаточно)

WhatType:

  • 1 - Достижение
  • 2 - Новый квест
  • 3 - Ошибка
  • 4 - Выносливость
  • 5 - Здоровье


Color: Цвет. В первых двух конструкторах используется цвет по умолчанию (Color:OrangeRed), а в четвертом - параметр 'leaveMeNull' отображается тем же цветом, что и текст игры.


Для примера:

  • public HUDMessage(string type, int number, bool add, Color color, Item messageSubject = null); - Подходит для кастомизации сообщения. Чаще всего используется для денег.
  • public HUDMessage(string message, string leaveMeNull) - Сообщение без иконки.
  • public HUDMessage(string message, Color color, float timeLeft, bool fadeIn) - Выводит сообщение, которое исчезает в течении установленного времени.


Примечание: - Все переменные являются публичными, кроме messageSubject, поэтому не стесняйтесь кастомизировать!


Пример: Всплывающее сообщение об Error-image-ingame.png ошибке:

Game1.addHUDMessage(new HUDMessage("MESSAGE", 3));

Меню

//добавить описание раздела

Получение информации о активной вкладки меню

Используйте Reflection, чтобы узнать какая вкладка GameMenu сейчас активна. GameMenu содержит вкладки Инвентарь, Навыки, Светское, Карта, Изготовление предметов, Коллекции, и Настройки в указанном порядке. То есть вкладка inventoryTab имеет индекс 0.

if (Game1.activeClickableMenu is GameMenu menu) {
  IList<IClickableMenu> pages = this.Helper.Reflection.GetField<List<IClickableMenu>>(menu, "pages").GetValue();
  IClickableMenu page = pages[menu.currentTab];

  // Получение вкладки Карта
  MapPage mapPage = (MapPage) pages[menu.currentTab];

  // Два примера проверки, что вкладка Карта открыта
  pages[menu.currentTab] is MapPage || menu.currentTab == GameMenu.mapTab;
}

Установка активной вкладки меню

Game1.activeClickableMenu = <Menu>

Harmony

“Here be dragons. Thou art forewarned.”

Harmony позволяет напрямую использовать методы игры. Это очень мощный инструмент, но есть серьезные оговорки:

  • Очень легко вызвать сбои, ошибки или неотлавливаемые баги.
  • Это может привести к затруднению диагностики ошибок повреждения памяти.
  • Кроссплатформенная совместимость не гарантируется и должна быть протестирована на всех трех платформах.
  • Может конфликтовать с другими модами Harmony (например, если два мода используют один и тот же метод, или два мода пытаются загрузить разные версии Harmony).
  • Патчи Harmony могут иметь непредсказуемые эффекты для других модов, которые не используют Harmony.

Использование Harmony должно быть последним средством, и поэтому намеренно не документировано.

Другое

Добавление небольшой анимации

location.temporarySprites.Add(new TemporaryAnimatedSprite(...))

Смотрите TemporaryAnimatedSprite для детальной информации

Воспроизведение звука

location.playSound("SOUND");

(e.g., "junimoMeep1")

Отправка письма

Используйте IAssetEditor, чтобы добавить новое письмо в Data\Mail.xnb. Затем вызывайте метод Game1.addMailForTomorrow, чтобы отправить его игроку.

 public static void addMailForTomorrow(string mailName, bool noLetter = false, bool sendToEveryone = false);

Где mailName ключ в Mail.xnb. Если использовать строку wizard где угодно в ключе, то письмо будет иметь волшебный фон[?] (начиная с 1.3) автоматически.

Исходные коды

Если что-то не получается, в большинстве случаев есть возможность подсмотреть реализацию в исходном коде другого мода. Смотрите столбец 'Исходный коды' в списке совместимых модификаций.