Перейти к содержанию

Рекомендуемые сообщения

Опубликовано (изменено)

Скачивание файла в игре в папку мода. Необходимо SKSE и Address Library. По желанию, можно вообще QtFramework подключить

pch.h

#pragma once

// This file is required.

#include "RE/Skyrim.h"
#include "SKSE/SKSE.h"

using namespace std::literals;
plugin.cpp

#include <Urlmon.h>
#include <iostream>
#include <filesystem>


#pragma comment (lib, "urlmon.lib")

void downloader(std::string url, std::string filename) {

    std::wstring urlstr = std::wstring(url.begin(), url.end());
    const wchar_t* urlcstr = urlstr.c_str();

    std::wstring fnamestr = std::wstring(filename.begin(), filename.end());
    const wchar_t* fnamecstr = fnamestr.c_str();


    URLDownloadToFile(0, urlcstr, fnamecstr, 0, 0);
}

SKSEPluginLoad(const SKSE::LoadInterface *skse) {
    SKSE::Init(skse);

    std::string url = "https://site.ru/file.txt";

    
    if(std::filesystem::exists("Data\\SKSE\\Plugins\\Plottering")) {
        SKSE::GetMessagingInterface()->RegisterListener([](SKSE::MessagingInterface::Message *message) {
        if (message->type == SKSE::MessagingInterface::kDataLoaded)
            RE::ConsoleLog::GetSingleton()->Print("Download File");
    });

        downloader(url, "Data\\SKSE\\Plugins\\Plottering\\file.txt");
    } else {
        SKSE::GetMessagingInterface()->RegisterListener([](SKSE::MessagingInterface::Message *message) {
        if (message->type == SKSE::MessagingInterface::kDataLoaded)
            RE::ConsoleLog::GetSingleton()->Print("Create dir");
    });
        std::filesystem::create_directory("Data\\SKSE\\Plugins\\Plottering");

        SKSE::GetMessagingInterface()->RegisterListener([](SKSE::MessagingInterface::Message *message) {
        if (message->type == SKSE::MessagingInterface::kDataLoaded)
            RE::ConsoleLog::GetSingleton()->Print("Download File");
    });
        downloader(url, "Data\\SKSE\\Plugins\\Plottering\\file.txt");
    }

    return true;
}


Изменено пользователем ac97
  • 9 месяцев спустя...
Опубликовано

Попытка реализации классов прям как в cpp, но только в Papyrus

 

Пример Класса:

Scriptname PlayerClass   

; Свойства
String Property Name Auto
Int Property Level Auto
Float Property Health Auto

; Конструктороподобная функция
Function Init(String name, Int level, Float health)
    Name = name
    Level = level
    Health = health
EndFunction

; Метод класса
Function PrintPlayerInfo()
    Debug.Notification("Player Name: " + Name)
    Debug.Notification("Player Level: " + Level)
    Debug.Notification("Player Health: " + Health)
EndFunction

Пример использования класса: 

Scriptname tClass extends Quest

; Свойство для хранения экземпляра класса Player

PlayerClass Property PlayerInstance Auto

Event OnInit()
	; Создание экземпляра класса Player
	PlayerInstance.Init("Dragonborn", 10, 100.0)

	; Вызов метода класса
	PlayerInstance.PrintPlayerInfo()
EndEvent

Function CleanupPlayerInstance()
	; аналог delete из cpp
	PlayerInstance = None
EndFunction
  • 1 год спустя...
Опубликовано (изменено)

Скрипт переноса зачарования. Работает с 2 ящиками, предусмотрен чёрный список. Требует UIExtensions для украшалок, заодно есть функция для получения кириллицы из UIExtensions. Скрипт должен быть сохранён в кодировке windows-1251.
 
sourceBox - ящик для предмета-источника
destinationBox - ящик для предмета-получателя
blackList - чёрный список, по которому проверяются предметы-источники
Скрипт вешается на кнопку, рычаг и т. п.

 

Пояснения.
Зачарования бывают зашитые в предмет изначально, бывают наложенные пользователем. С точки зрения скрипта эти зачарования обрабатываются по-разному.

 

Функция GetNthForm возвращает базовую форму предмета. С базовой формы можно получить зашитое зачарование, но только с дочерних классов Weapon и Armor, поэтому в скрипте Form приводится к Armor и Weapon. Исходя из того, какое приведение удалось, идёт дальнейшая логика определения подтипа предмета.

 

Чтобы получить пользовательское зачараование, а также заряд, нужна ссылка на конкретный экземпляр предмета. Её невозможно получить, пока предмет в контейнере, поэтому предмет из контейнера выбрасывается с помощью функции DropObject. Визуально предмет просто оказывается рядом с контейнером, но поскольку он будет быстро убран обратно, это не должно быть проблемой. Это много где используется, например, в стойках.

После получения всех необходимых данных, предмет убирается обратно с помощью функции AddItem. Эта функция в некотором смысле универсальна. Если передать ей ссылку на предмет (ObjectReference), то в контейнер будет перемещён именно этот предмет, а если передать Form или FormList, то будут созданы новые экземпляры предмета из базовой формы.

 

Несмотря на то, что я тестировал скрипт в доме игрока, предмет в процессе становится ворованным. Я пробовал установить владельца ящика - это не помогло. Менять владельца зоны я не рискнул, так как это может привести к непредсказуемым последсвиям. Мне помогло принудительно установить, что у предмета нет владельца, если у предмета нет владельца. Такой вот костыль.

 

Такой же фокус проводится с предметом получателем, постольку чары должны быть наложены именно на экземпляр (ObjectReference). Если наложить на базовую форму, это изменит все копии в мире.

 

Украшалки с формированием вариантов нового названия оставлю без комментариев, это не относится к изначальной задаче.

Отмечу только, что функция Cyrilic чинит текст, который выглядит, как набор латинских букв с диакритиками (чешский, кажется, алфавит). Работает, даже если текст частично правильный, частично кракозябры.

Scriptname aaachuTransButtonScript extends ObjectReference  

ObjectReference Property sourceBox Auto
ObjectReference Property destinationBox Auto
Form[] Property blackList Auto

Event OnActivate(ObjectReference akActionRef)
	If sourceBox.GetNumItems() == 0
		Debug.Notification("В ящике основы ничего нет")
		Return
	EndIf
	If sourceBox.GetNumItems() != 1
		Debug.Notification("В ящике основы больше одного предмета")
		Return
	EndIf
	Form sForm = sourceBox.GetNthForm(0)
	If blackList.Find(sForm) != -1
		Debug.Notification("В ящике основы запрещённый предмет")
		Return
	EndIf

	If destinationBox.GetNumItems() == 0
		Debug.Notification("В ящике результата ничего нет")
		Return
	EndIf
	If destinationBox.GetNumItems() != 1
		Debug.Notification("В ящике результата больше одного предмета")
		Return
	EndIf

	Armor sArmor = sForm as Armor
	Weapon sWeapon = sForm as Weapon

	Form dForm = destinationBox.GetNthForm(0)

	Enchantment ench
	Float maxCharge = 0
	String sClass

	If sArmor
		sClass = "броня"
		ench = sArmor.GetEnchantment() ;получение ванильного энчанта

		Armor dArmor = dForm as Armor
		If !dArmor
			Debug.Notification("В ящике результата не броня")
			Return
		EndIf
		If dArmor.GetEnchantment()
			Debug.Notification("В ящике результата броня с чарами")
			Return
		EndIf

		String sType = GetArmorType(sArmor)
		If !sType
			Debug.Notification("В ящике основы броня неизвестного типа")
			Return
		EndIf

		String dType = GetArmorType(dArmor)
		If !dType
			Debug.Notification("В ящике результата броня неизвестного типа")
			Return
		EndIf

		If dType != sType
			Debug.Notification("В ящиках броня разного типа: " + sType + " и " + dType)
			Return
		EndIf
	ElseIf sWeapon
		sClass = "оружие"
		ench = sWeapon.GetEnchantment() ;получение ванильного энчанта

		Weapon dWeapon = destinationBox.GetNthForm(0) as Weapon
		If !dWeapon
			Debug.Notification("В ящике результата не оружие")
			Return
		EndIf
		If dWeapon.GetEnchantment()
			Debug.Notification("В ящике результата оружие с чарами")
			Return
		EndIf

		String sType = GetWeaponType(sWeapon)
		If sType == ""
			Debug.Notification("В ящике основы оружие неизвестного типа")
			Return
		EndIf

		String dType = GetWeaponType(dWeapon)
		If dType == ""
			Debug.Notification("В ящике результата оружие неизвестного типа")
			Return
		EndIf

		If dType != sType
			Debug.Notification("В ящиках оружие разного типа: " + sType + " и " + dType)
			Return
		EndIf
	Else
		Debug.Notification("В ящике основы не броня и не оружие")
		Return
	EndIf

	ObjectReference sRef = sourceBox.DropObject(sForm, 1)
	If !sRef
		Debug.Notification("Не удаётся получить экземпряр основы")
		Return
	EndIf
	If !ench
		ench = sRef.GetEnchantment() ;получение пользовательского энчанта
	EndIf

	maxCharge = sRef.GetItemMaxCharge()

	If CheckOwner(sRef)
		Debug.Notification("Владелец основы сохранён")
	EndIf

	String sName = sRef.GetDisplayName()

	sourceBox.AddItem(sRef, 1, true)

	If !ench
		Debug.Notification("В ящике основы " + sClass + " без чар")
		Return
	EndIf
	Debug.Notification("Заряд: " + maxCharge)

	String dName = dForm.GetName()

	String[] variants = new String[10]
	variants[0] = dName
	Int num = 1
	Int pos = StringUtil.Find(sName, " ")
	While pos != -1 && num < 10
		variants[num] = dName + StringUtil.Substring(sName, pos)
		num += 1
		pos = StringUtil.Find(sName, " ", pos + 1)
	EndWhile
	Int count = num

	uilistmenu menu = uiextensions.GetMenu("UIListMenu") as uilistmenu
	num = 0
	While num < count
		menu.AddEntryItem(variants[num])
		num += 1
	EndWhile
	menu.AddEntryItem("Свой вариант")
	menu.OpenMenu()
	Int result = menu.GetResultInt()
	If result != 0
		If result == count
			uitextentrymenu textMenu = uiextensions.GetMenu("uitextentrymenu") as uitextentrymenu
			textMenu.SetPropertyString("text", dName)
			textMenu.OpenMenu()
			String customName = Cyrilic(textMenu.GetResultString())
			If customName == ""
				Debug.Notification("Введено пустое название, сохранён оригинал")
			Else
				dName = customName
				; получение разбайтовки для написания функции Cyrilic, оставлено на память
				; Int cNum = 0
				; Int len = StringUtil.GetLength(customName)
				; String ord = ""
				; While cNum < len
				; 	ord = ord + StringUtil.AsOrd(StringUtil.Substring(customName, cNum, 1)) + ","
				; 	cNum += 1
				; EndWhile
				; Debug.Trace(ord)
			EndIf
		Else
			dName = variants[result]
		EndIf
	EndIf

	ObjectReference dRef = destinationBox.DropObject(dForm, 1)
	If !dRef
		Debug.Notification("Не удаётся получить экземпляр результата")
		Return
	EndIf

	If dRef.GetEnchantment()
		Debug.Notification("В ящике результата " + sClass + " с чарами")
		If CheckOwner(dRef)
			Debug.Notification("Владелец результата сохранён")
		EndIf
		destinationBox.AddItem(dRef, 1, true)
		Return
	EndIf

	dRef.SetDisplayName(dName, False)
	dRef.SetEnchantment(ench, maxCharge)

	If CheckOwner(dRef)
		Debug.Notification("Владелец результата сохранён")
	EndIf

	destinationBox.AddItem(dRef, 1, true)
	Debug.Notification("Создано: " + dName)

	menu = uiextensions.GetMenu("UIListMenu") as uilistmenu
	menu.AddEntryItem("Уничтожить оригинал")
	menu.AddEntryItem("Сохранить оригинал")
	menu.OpenMenu()
	result = menu.GetResultInt()
	If result == 0
		sourceBox.RemoveItem(sForm, 1, True)
		Debug.Notification("Уничтожено: " + sName)
	EndIf
EndEvent

Bool Function CheckOwner(ObjectReference ref) ;костыль, даже если у предмета нет владельца, он помечается краденым
	If ref.GetActorOwner() == None && ref.GetFactionOwner() == None
		ref.SetActorOwner(None) ;казалось бы, уже None, ставлю None, но статус ворованного снимается
		Return False
	Else
		Return True
	EndIf
EndFunction

String Function GetArmorType(Armor akArmor)
	If akArmor.HasKeywordString("ArmorHelmet") || akArmor.HasKeywordString("clothinghead") || akArmor.HasKeywordString("clothingcirclet")
		Return "шлем/капюшон/обруч"
	ElseIf akArmor.HasKeywordString("ArmorCuirass") || akArmor.HasKeywordString("clothingbody")
		Return "кираса/роба"
	ElseIf akArmor.HasKeywordString("ArmorGauntlets") || akArmor.HasKeywordString("clothinghands")
		Return "перчатки"
	ElseIf akArmor.HasKeywordString("ArmorBoots") || akArmor.HasKeywordString("clothingfeet")
		Return "сапоги/ботинки"
	ElseIf akArmor.HasKeywordString("ArmorShield")
		Return "щит"
	ElseIf akArmor.HasKeywordString("clothingring")
		Return "кольцо"
	ElseIf akArmor.HasKeywordString("clothingnecklace")
		Return "ожерелье"
	Else
		Return ""
	EndIf
EndFunction

String Function GetWeaponType(Weapon akWeapon)
	If akWeapon.HasKeywordString("WeapTypeBattleaxe")
		Return "секира"
	ElseIf akWeapon.HasKeywordString("WeapTypeBow")
		Return "лук"
	ElseIf akWeapon.HasKeywordString("WeapTypeDagger")
		Return "кинжал"
	ElseIf akWeapon.HasKeywordString("WeapTypeGreatsword")
		Return "двуручный меч"
	ElseIf akWeapon.HasKeywordString("WeapTypeMace")
		Return "булава"
	ElseIf akWeapon.HasKeywordString("WeapTypeStaff")
		Return "посох"
	ElseIf akWeapon.HasKeywordString("WeapTypeSword")
		Return "меч"
	ElseIf akWeapon.HasKeywordString("WeapTypeWarAxe")
		Return "топор"
	ElseIf akWeapon.HasKeywordString("WeapTypeWarhammer")
		Return "молот"
	Else
		Return ""
	EndIf
EndFunction

String Function Cyrilic(String s) ;магия! кстати, чтобы всё работало, скрипт должен быть сохранён в кодировке windows-1251, ради этого, собственно, и пляски с байтами
	String cyr = ""
	Int pos = 0
	Int len = StringUtil.GetLength(s)
	While pos < len
		String c = StringUtil.Substring(s, pos, 1)
		Int b = StringUtil.AsOrd(c)
		If b == -61
			pos += 1
			String cc = StringUtil.Substring(s, pos, 1)
			b = StringUtil.AsOrd(cc)
			If b == -96
				cyr = cyr + "а"
			ElseIf b == -95
				cyr = cyr + "б"
			ElseIf b == -94
				cyr = cyr + "в"
			ElseIf b == -93
				cyr = cyr + "г"
			ElseIf b == -92
				cyr = cyr + "д"
			ElseIf b == -91
				cyr = cyr + "е"
			ElseIf b == -90
				cyr = cyr + "ж"
			ElseIf b == -89
				cyr = cyr + "з"
			ElseIf b == -88
				cyr = cyr + "и"
			ElseIf b == -87
				cyr = cyr + "й"
			ElseIf b == -86
				cyr = cyr + "к"
			ElseIf b == -85
				cyr = cyr + "л"
			ElseIf b == -84
				cyr = cyr + "м"
			ElseIf b == -83
				cyr = cyr + "н"
			ElseIf b == -82
				cyr = cyr + "о"
			ElseIf b == -81
				cyr = cyr + "п"
			ElseIf b == -80
				cyr = cyr + "р"
			ElseIf b == -79
				cyr = cyr + "с"
			ElseIf b == -78
				cyr = cyr + "т"
			ElseIf b == -77
				cyr = cyr + "у"
			ElseIf b == -76
				cyr = cyr + "ф"
			ElseIf b == -75
				cyr = cyr + "х"
			ElseIf b == -74
				cyr = cyr + "ц"
			ElseIf b == -73
				cyr = cyr + "ч"
			ElseIf b== -72
				cyr = cyr + "ш"
			ElseIf b == -71
				cyr = cyr + "щ"
			ElseIf b == -70
				cyr = cyr + "ъ"
			ElseIf b == -69
				cyr = cyr + "ы"
			ElseIf b == -68
				cyr = cyr + "ь"
			ElseIf b == -67
				cyr = cyr + "э"
			ElseIf b == -66
				cyr = cyr + "ю"
			ElseIf b == -65
				cyr = cyr + "я"
			ElseIf b == -128
				cyr = cyr + "А"
			ElseIf b == -127
				cyr = cyr + "Б"
			ElseIf b == -126
				cyr = cyr + "В"
			ElseIf b == -125
				cyr = cyr + "Г"
			ElseIf b == -124
				cyr = cyr + "Д"
			ElseIf b == -123
				cyr = cyr + "Е"
			ElseIf b == -122
				cyr = cyr + "Ж"
			ElseIf b == -121
				cyr = cyr + "З"
			ElseIf b == -120
				cyr = cyr + "И"
			ElseIf b == -119
				cyr = cyr + "Й"
			ElseIf b == -118
				cyr = cyr + "К"
			ElseIf b == -117
				cyr = cyr + "Л"
			ElseIf b == -116
				cyr = cyr + "М"
			ElseIf b == -115
				cyr = cyr + "Н"
			ElseIf b == -114
				cyr = cyr + "О"
			ElseIf b == -113
				cyr = cyr + "П"
			ElseIf b == -112
				cyr = cyr + "Р"
			ElseIf b == -111
				cyr = cyr + "С"
			ElseIf b == -110
				cyr = cyr + "Т"
			ElseIf b == -109
				cyr = cyr + "У"
			ElseIf b == -108
				cyr = cyr + "Ф"
			ElseIf b == -107
				cyr = cyr + "Х"
			ElseIf b == -106
				cyr = cyr + "Ц"
			ElseIf b == -105
				cyr = cyr + "Ч"
			ElseIf b == -104
				cyr = cyr + "Ш"
			ElseIf b == -103
				cyr = cyr + "Щ"
			ElseIf b == -102
				cyr = cyr + "Ъ"
			ElseIf b == -101
				cyr = cyr + "Ы"
			ElseIf b == -100
				cyr = cyr + "Ь"
			ElseIf b == -99
				cyr = cyr + "Э"
			ElseIf b == -98
				cyr = cyr + "Ю"
			ElseIf b == -97
				cyr = cyr + "Я"
			Else
				cyr = cyr + c + cc
			EndIf
		ElseIf b == -62
			pos += 1
			String cc = StringUtil.Substring(s, pos, 1)
			b = StringUtil.AsOrd(cc)
			If b == -72
				cyr = cyr + "ё"
			ElseIf b == -88
				cyr = cyr + "Ё"
			Else
				cyr = cyr + c + cc
			EndIf
		Else
			cyr = cyr + c
		EndIf
		pos += 1
	EndWhile
	Return cyr
EndFunction

 

Изменено пользователем begemot1451
Опубликовано

Скрипт для снятия с вещей статуса краденного. Вешается на кнопку/рычаг, очищает вещи из контейнера.
whiteBox - ящик
Собирает в массив список предметов, которые есть в сундуке, для каждой вещи получает её количество. Выкидывает вещи поштучно, собирая ссылки на выкинутые предметы во второй массив.
Устанавливает всем ссылкам отсутствие владельца, кладёт обратно в сундук.
Зачем так много циклов.
1. отдельный цикл по формам нужен потому, что после запихивания очередной вещи в сундук очерёдность в сундуке меняется, поэтому надо сразу получить весь список.
2. отдельный цикл по предметам потому, что надо выкинуть весь стак, а потом уже запихивать обратно, иначе скорее всего пометка останется. Если вы искали краденную вещь в стаке рукуми, вы поймёте.

Scriptname aaachuWhiteBoxButton extends ObjectReference 

ObjectReference Property whiteBox Auto

Event OnActivate(ObjectReference akActionRef)
    ObjectReference[] refs = new ObjectReference[128]
    Form[] forms = new Form[128]
    Int fCount = whiteBox.GetNumItems()
    If fCount > 128
        Debug.Notification("Слишком много предметов")
        Return
    EndIf
    Int i = 0
    While i < fCount
        forms[i] = whiteBox.GetNthForm(i)
        i += 1
    EndWhile
    i = 0
    While i < fCount
        Form akForm = forms[i]
        Int iCount = whiteBox.GetItemCount(akForm)
        If iCount > 128
            Debug.Notification("Слишком много предметов " + akForm.GetName())
            Return
        EndIf
        Int j = 0
        While j < iCount
            refs[j] = whiteBox.DropObject(akForm, 1)
            j += 1
        EndWhile
        j = 0
        While j < iCount
            refs[j].SetActorOwner(None)
            refs[j].SetFactionOwner(None)
            whiteBox.AddItem(refs[j], 1, true)
            j += 1
        EndWhile
        Debug.Notification("Очищено " + iCount + " " + akForm.GetName())
        i += 1
    EndWhile
EndEvent

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйте новый аккаунт в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...