Собираем рабочие скрипты здесь, большие и малые, легкие и сложные (Новичкам всё трудно). К скрипту прилагаем описание работы. Скрипты оформлять доступно, можно с построчными комментариями. На один пост - один скрипт (Позже, когда тема разрастется, будет сделана навигация по теме с быстрым переходом к постам)
Если скрипт не Ваш (был написан для Вас когда-то в прошлом), указывайте пожалуйста автора.
P.S. Если скрипт не рабочий, Вы пишите об этом здесь. (Только вы должны удостовериться, что скрипт действительно не работает). Далее приводим его в рабочее состояние. В теме соблюдаем чистоту.
P.P.S Оптимизация кода - важный элемент. Если Вы можете оптимизировать работу скрипта, сделайте это и выложите здесь. Исходный скрипт будет обновлен.

#41
Отправлено
- Domastir D'Morte, Gorv, werr и 4 другим это нравится
#43
Отправлено
Воспроизводим свои видео:
Синтаксис
Function PlayBink(string asFileName, bool abInterruptible = false, bool abMuteAudio = true, bool abMuteMusic = true, \ bool abLetterbox = true) native global
Пример скрипта:
Scriptname aaaTestVideo extends ObjectReference Event onActivate(ObjectReference akActionRef) Game.PlayBink("BGS_Logo.bik", false, true, true, true) Game.GetPlayer().AddItem(money, 1000) endEvent MiscObject Property money Auto
Скрипт, при активации чего-либо, воспроизводит видео, а после выдает деньги.
Пример в игре:
Сообщение отредактировал ac97: 13 апреля 2021 - 22:38
#44
Отправлено
Scriptname aaaGetReputationHunter extends ObjectReference GlobalVariable Property countRep Auto //Глобальная переменная с текущим кол-вом репутации MiscObject Property plamen Auto //Ресурс необходимый для сдачи, для прокачки репутации EVENT onActivate(objectReference actronaut) int countReputation = countRep.GetValueInt() //получаем текущее кол-во репутации int countKristall = Game.GetPlayer().GetItemCount(plamen) //получаем кол-во артефактов у персонажа на руках. if(countReputation >= 0 && countReputation < 500 && countKristall >= 1) countRep.Value += 25 Game.GetPlayer().RemoveItem(plamen, 1) //Если репутации до 500 и есть артефакт для прокачки, то добавляем 25 репутации и удаляем артефакт elseif(countReputation <= 1000 && countReputation >= 500 && countKristall >= 2) countRep.Value += 25 Game.GetPlayer().RemoveItem(plamen, 2) //Если репутации от 500 и до 1000 и есть артефакт для прокачки, то добавляем 25 репутации и удаляем артефакт elseif(countReputation <= 2000 && countReputation >= 1000 && countKristall >= 3) countRep.Value += 25 Game.GetPlayer().RemoveItem(plamen, 3) //Если репутации от 1000 и до 2000 и есть артефакт для прокачки, то добавляем 25 репутации и удаляем артефакт elseif(countReputation <= 3000 && countReputation >= 2000 && countKristall >= 4) countRep.Value += 25 Game.GetPlayer().RemoveItem(plamen, 4) //Если репутации от 2000 и до 3000 и есть артефакт для прокачки, то добавляем 25 репутации и удаляем артефакт elseif(countReputation >= 3000) Debug.MessageBox("Максимальное кол-во репутации для сдачи. Выполните квест на получение максимальной репутации.") else Debug.MessageBox("Недостаточно Кристаллов Ящера") endif endEVENT
Скрипт для прокачки репутации любой Вами созданной гильдии. =)
Scriptname aaaShopHunters extends ObjectReference Message Property msgHunters Auto Potion Property grayPotion Auto Potion Property greenPotion Auto Potion Property bluePotion Auto Potion Property phioletPotion Auto Potion Property redPotion Auto MiscObject Property money Auto GlobalVariable Property reputation Auto EVENT onActivate(objectReference actronaut) int response = msgHunters.Show() int rep = reputation.GetValueInt() if (response == 0) if (rep >= 500 && game.getplayer().getItemCount(money) >= 50) Game.GetPlayer().RemoveItem(money, 50) Game.GetPlayer().AddItem(grayPotion, 1) else Debug.MessageBox("Недостаточно денег или репутации") endif elseif (response == 1) if (rep >= 1000 && game.getplayer().getItemCount(money) >= 70) Game.GetPlayer().RemoveItem(money, 70) Game.GetPlayer().AddItem(greenPotion, 1) else Debug.MessageBox("Недостаточно денег или репутации") endif elseif (response == 2) if (rep >= 2000 && game.getplayer().getItemCount(money) >= 100) Game.GetPlayer().RemoveItem(money, 100) Game.GetPlayer().AddItem(bluePotion, 1) else Debug.MessageBox("Недостаточно денег или репутации") endif elseif (response == 3) if (rep >= 3000 && game.getplayer().getItemCount(money) >= 150) Game.GetPlayer().RemoveItem(money, 150) Game.GetPlayer().AddItem(phioletPotion, 1) else Debug.MessageBox("Недостаточно денег или репутации") endif elseif (response == 4) if (rep >= 4000 && game.getplayer().getItemCount(money) >= 300) Game.GetPlayer().RemoveItem(money, 300) Game.GetPlayer().AddItem(redPotion, 1) else Debug.MessageBox("Недостаточно денег или репутации") endif elseif (response == 5) else Debug.MessageBox("Error") endif endEVENT
Реализация репутационного магазина, для покупки товаров с кол-вом репутации данной гильдии.
#45
Отправлено
String Function IntToHexString(Int Value) Bool Negative = (Value < 0) Int Temp01 = Math.Abs(Value) as Int Int Temp02 = 0 Int Temp03 = 0 String TempResult = "" While (Temp01 != 0) Temp02 = Math.Floor(Temp01 / 16) Temp03 = Temp01 - 16 * Temp02 TempResult = TempResult + StringUtil.GetNthChar("0123456789ABCDEF", Temp03) Temp01 = Temp02 EndWhile String Result = "" Int Index = StringUtil.GetLength(TempResult) While (Index > 0) Index = Index - 1 Result = Result + StringUtil.GetNthChar(TempResult, Index) EndWhile If (Negative) Return ("-" + Result) EndIf Return Result EndFunction
Перевод из Hex в Dec (String в Int, пример: "A56BC7" ➔ 10841031):
Int Function HexStringToInt(String Value) Int Result = 0 Bool Negative = (StringUtil.GetNthChar(Value, 0) == "-") Int Index = 0 Int ValueLength = StringUtil.GetLength(Value) While (Index < ValueLength) String Char = StringUtil.GetNthChar(Value, Index) Int Pos = StringUtil.Find("0123456789ABCDEF", Char, 0) If (Pos != -1) Result += Pos * Math.Pow(16, ValueLength - Index - 1) as Int EndIf Index += 1 EndWhile If (Negative) Return -Result EndIf Return Result EndFunction
Поддерживаются отрицательные числа. Требуется SKSE из-за StringUtil. Примеры использования:
String ValueHex = IntToHexString(481516) ; "758EC" Int ValueDec = HexStringToInt("ABC123") ; 11256099
————————————
don't forget your falls
————————————
#46
Отправлено
ScriptName SetPerkPointsScript Extends ReferenceAlias Event OnInit() RegisterForMenu("Console") ; Debug.Trace("[SetPerkPointsScript] console menu registered") EndEvent Event OnMenuOpen(String MenuName) RegisterForKey(28) ; enter RegisterForKey(156) ; num enter ; Debug.Trace("[SetPerkPointsScript] key 28 (enter) and key 156 (num enter) registered") EndEvent Event OnMenuClose(String MenuName) UnregisterForAllKeys() ; Debug.Trace("[SetPerkPointsScript] all keys unregistered") EndEvent Event OnKeyDown(Int KeyCode) ; Debug.Trace("[SetPerkPointsScript] key 28 (enter) or key 156 (num enter) pressed") Int CommandIndex = UI.GetInt("Console", "_global.Console.ConsoleInstance.Commands.length") - 1 ; Debug.Trace("[SetPerkPointsScript] Int CommandIndex >> " + CommandIndex as String) String LatestCommand = UI.GetString("Console", "_global.Console.ConsoleInstance.Commands." + CommandIndex as String) ; Debug.Trace("[SetPerkPointsScript] String LatestCommand >> " + LatestCommand) String[] CommandParts = StringUtil.Split(LatestCommand, " ") ExecCommand(CommandParts[0], CommandParts) EndEvent Function ExecCommand(String CommandName, String[] CommandArray) ; Debug.Trace("[SetPerkPointsScript] String CommandName >> " + CommandName) If (CommandName == "SetPerkPoints") || (CommandName == "SPP") If (CommandArray.Length == 2) Int PointsToSet = CommandArray[1] as Int If (PointsToSet < 0) PointsToSet = 0 ElseIf (PointsToSet > 255) PointsToSet = 255 EndIf Game.SetPerkPoints(PointsToSet) ConsoleUtil.PrintMessage("Player perk points count successfully set to " + PointsToSet as String) Else ConsoleUtil.PrintMessage("Error! Wrong function syntax. Usage:\nSetPerkPoints <int>\nSPP <int>") EndIf EndIf EndFunctionСкрипт прикрепляется к alias'у с игроком в квесте, который стартует при первой установке мода. При нажатии клавиши Enter или Num Enter будет запущена функция ExecCommand с двумя аргументами - названием команды и массивом из всех элементов команды. Так, в моём примере при вводе команды "spp 136" функции будут переданы аргументы "spp" и ["spp", "136"]. Обратите внимание, что все аргументы строковые, так что вам может потребоваться каст.
————————————
don't forget your falls
————————————
#47
Отправлено
Int[] Function ColorToRGB(Int Value) Int[] Result = New Int[3] Result[0] = Math.RightShift(Math.LogicalAnd(Value, 0xFF0000), 16) ; red Result[1] = Math.RightShift(Math.LogicalAnd(Value, 0xFF00), 8) ; green Result[2] = Math.RightShift(Math.LogicalAnd(Value, 0xFF), 0) ; blue Return Result EndFunction
Этот вид функции полностью рабочий, но я привёл его таким, лишь чтобы показать алгоритм действий. Если подумать, то смещение на 0 бит не имеет смысла, как и "логическое И" с 0xFF0000 в связке со смещением на 16 бит. Без "логического И" ABCDEF после смещения превращается в AB.CDEF, которое сразу обрезается до AB из-за типа данных Int. Таким образом, более оптимальный вид функции будет таким:
Int[] Function ColorToRGB(Int Value) Int[] Result = New Int[3] Result[0] = Math.RightShift(Value, 16) ; red Result[1] = Math.RightShift(Math.LogicalAnd(Value, 0xFF00), 8) ; green Result[2] = Math.LogicalAnd(Value, 0xFF) ; blue Return Result EndFunction
Пример использования:
Int[] RGB = ColorToRGB(10092543) ; [153, 255, 255]
————————————
don't forget your falls
————————————
#48
Отправлено
Когда в SkyUI вы используете настройку типа OptionColor (выбор цвета из небольшой палитры), то мод возвращает цвет в формате Int (целое число). Например, светло-голубой цвет будет иметь значение 10092543. Вам может понадобиться вытащить из этого значения числа RGB, для чего некоторые предлагают операции деления, вычитания или целого остатка. Да, эти методы рабочие, но это квадратно-гнездовой способ мышления, когда есть битовые операции. Выглядит это вот так:
Int[] Function ColorToRGB(Int Value) Int[] Result = New Int[3] Result[0] = Math.RightShift(Math.LogicalAnd(Value, 0xFF0000), 16) ; red Result[1] = Math.RightShift(Math.LogicalAnd(Value, 0xFF00), 8) ; green Result[2] = Math.RightShift(Math.LogicalAnd(Value, 0xFF), 0) ; blue Return Result EndFunctionЭтот вид функции полностью рабочий, но я привёл его таким, лишь чтобы показать алгоритм действий. Если подумать, то смещение на 0 бит не имеет смысла, как и "логическое И" с 0xFF0000 в связке со смещением на 16 бит. Без "логического И" ABCDEF после смещения превращается в AB.CDEF, которое сразу обрезается до AB из-за типа данных Int. Таким образом, более оптимальный вид функции будет таким:Int[] Function ColorToRGB(Int Value) Int[] Result = New Int[3] Result[0] = Math.RightShift(Value, 16) ; red Result[1] = Math.RightShift(Math.LogicalAnd(Value, 0xFF00), 8) ; green Result[2] = Math.LogicalAnd(Value, 0xFF) ; blue Return Result EndFunctionПример использования:Int[] RGB = ColorToRGB(10092543) ; [153, 255, 255]
Теперь осталось реализовать структуры, классы, шаблоны да и полностью библиотеку STL =)
#49
Отправлено
Раздевает и одевает ГГ по триггеру... Если что лишнее, буду рад замечаниям...
Scriptname aaaUnequip extends ObjectReference
Import Game
Import Utility
Import Debug
Import MathFormlist Property frmList auto
Event OnTriggerEnter(ObjectReference akActionRef)
if(akActionRef == Game.GetPlayer())
actor who = akActionRef as actor
frmList.Revert()
UnequipWeaponActor(who)
UnequipItemActor(who)
endifEndEvent
EVENT OnTriggerLeave (objectReference akActionRef)
If akActionRef == Game.GetPlayer()
actor who = akActionRef as actor
EquipItemActor(who)
EndIf
EndEventFunction UnequipItemActor(Actor target)
int index
int slotsChecked
slotsChecked += 0x00100000
slotsChecked += 0x00200000 ; игнорировать зарезервированные слоты
slotsChecked += 0x80000000int thisSlot = 0x01
while (thisSlot < 0x80000000)
if (Math.LogicalAnd(slotsChecked, thisSlot) != thisSlot)
Armor thisArmor = target.GetWornForm(thisSlot) as Armor
if (thisArmor)
frmList.AddForm(thisArmor)
target.UnequipItem(thisArmor, abSilent = true)
index += 1
slotsChecked += thisArmor.GetSlotMask()
else
slotsChecked += thisSlot
endif
endif
thisSlot *= 2 ;удвоить число, чтобы перейти к следующему слоту
endWhile
EndFunctionFunction EquipItemActor(Actor akActor)
Int iIndex = frmList.GetSize()
While iIndex
iIndex -= 1
Form kForm = frmList.GetAt(iIndex) As form
akActor.EquipItem(kForm, abSilent = true)
EndWhile
frmList.Revert()
EndFunctionFunction UnequipWeaponActor(Actor target)
if (target.GetEquippedWeapon(true))
FORM twisWeapon=target.GetEquippedWeapon(true) as FORM
frmList.AddForm(twisWeapon)
target.UnequipItem(twisWeapon, abSilent = true)
endif
if (target.GetEquippedWeapon(false))
FORM twisWeapon=target.GetEquippedWeapon(false) as FORM
frmList.AddForm(twisWeapon)
target.UnequipItem(twisWeapon, abSilent = true)
endif
EndFunction
зы... нужно в ск формлист создать пустой и подключить к скриптуб, и прошу не тыкать пальцем с усмешкой. это мой первый скрипт
Решил опробовать скрипт, но словил ошибки компиляции
#50
Отправлено
Скрипт для ванны/бассейна/бадьи и т.д. Предназначен для вампиров. Если человек будет использовать, то проиграется только сообщение с отвращением и анимация.
Scriptname GK_script_bath extends ObjectReference EffectShader Property DLC1nVampireGoreFXS Auto MagicEffect Property PERKEFFECT Auto String Property Fail Auto String Property Success Auto String Property MyAnimation_01 Auto Idle Property MyAnimation_02 Auto Idle Property MyAnimation_03 Auto String Property MyAnimation_04 Auto String Property MyAnimation_05 Auto Idle Property IdleStop_Loose Auto ObjectReference Property PlayerRef Auto ObjectReference Property MovetoInside Auto ObjectReference Property MovetoOutside Auto Sound Property WashesTheBody01 Auto Sound Property WashesTheBody02 Auto Sound Property SitsInTheBath01 Auto Sound Property SitsInTheBath02 Auto Sound Property GetsUpInTheBath01 Auto Sound Property GetsUpInTheBath02 Auto Sound Property WipesOff Auto Sound Property Vomit Auto Spell Property PerkSpell1 Auto Spell Property PerkSpell2 Auto Spell Property HasVampirism Auto GlobalVariable Property GameHour Auto ImageSpaceModifier Property TG05BlackFrame Auto Event OnActivate(ObjectReference akActionRef) If akActionRef == Game.GetPlayer().HasSpell(HasVampirism) == 0 If Game.GetPlayer().IsWeaponDrawn() Game.DisablePlayerControls(abMovement =true, abFighting = true, abCamSwitch = true, abLooking = true, abSneaking = true, abMenu = true, abJournalTabs= true) Utility.Wait(1.5) Game.EnablePlayerControls(abMovement =true, abFighting = true, abCamSwitch = true, abLooking = true, abSneaking = true, abMenu = true, abJournalTabs= true) EndIf Game.DisablePlayerControls(abMovement =true, abFighting = true, abCamSwitch = true, abLooking = false, abSneaking = true, abMenu = true, abJournalTabs= true) Game.ForceThirdPerson() Utility.Wait(0.5) debug.notification(Fail) Debug.SendAnimationEvent(Game.GetPlayer(), MyAnimation_04) Vomit.Play(PlayerRef) PerkSpell2.Cast(Game.GetPlayer(), Game.GetPlayer()) Utility.Wait(1.5) Game.GetPlayer().PlayIdle(IdleStop_Loose) Game.EnablePlayerControls(abMovement =true, abFighting = true, abCamSwitch = true, abLooking = false, abSneaking = true, abMenu = true, abJournalTabs= true) Return Else If akActionRef == Game.GetPlayer().HasSpell(HasVampirism) == 1 If Game.GetPlayer().IsWeaponDrawn() Game.DisablePlayerControls(abMovement =true, abFighting = true, abCamSwitch = true, abLooking = true, abSneaking = true, abMenu = true, abJournalTabs= true) Utility.Wait(1.5) Game.EnablePlayerControls(abMovement =true, abFighting = true, abCamSwitch = true, abLooking = true, abSneaking = true, abMenu = true, abJournalTabs= true) EndIf Game.DisablePlayerControls(abMovement =true, abFighting = true, abCamSwitch = true, abLooking = false, abSneaking = true, abMenu = true, abJournalTabs= true) Game.ForceThirdPerson() Utility.Wait(0.5) Debug.SendAnimationEvent(Game.GetPlayer(), MyAnimation_05) Utility.Wait(2.0) TG05BlackFrame.ApplyCrossFade() Utility.Wait(3.5) Game.GetPlayer().UnequipAll() Game.GetPlayer().Moveto(MovetoInside) Utility.Wait(0.5) Debug.SendAnimationEvent(Game.GetPlayer(), MyAnimation_01) TG05BlackFrame.Remove() SitsInTheBath01.Play(PlayerRef) Utility.Wait(2.0) DLC1nVampireGoreFXS.Play(Game.GetPlayer()) Game.GetPlayer().PlayIdle(MyAnimation_02) GetsUpInTheBath01.Play(PlayerRef) Utility.Wait(2.7) Game.GetPlayer().PlayIdle(MyAnimation_03) WashesTheBody01.Play(PlayerRef) Utility.Wait(2.0) DLC1nVampireGoreFXS.Stop(Game.GetPlayer()) Utility.Wait(1.0) Debug.SendAnimationEvent(Game.GetPlayer(), MyAnimation_01) SitsInTheBath02.Play(PlayerRef) Utility.Wait(2.0) DLC1nVampireGoreFXS.Play(Game.GetPlayer()) Game.GetPlayer().PlayIdle(MyAnimation_02) GetsUpInTheBath02.Play(PlayerRef) Utility.Wait(2.7) Game.GetPlayer().PlayIdle(MyAnimation_03) WashesTheBody02.Play(PlayerRef) TG05BlackFrame.ApplyCrossFade() Utility.Wait(2.0) WipesOff.Play(PlayerRef) Utility.Wait(3.0) DLC1nVampireGoreFXS.Stop(Game.GetPlayer()) Game.GetPlayer().PlayIdle(IdleStop_Loose) Game.GetPlayer().Moveto(MovetoOutside) Game.EnablePlayerControls(abMovement =true, abFighting = true, abCamSwitch = true, abLooking = false, abSneaking = true, abMenu = true, abJournalTabs= true) GameHour.SetValue(GameHour.GetValue()+1) debug.notification("Прошёл один час") PerkSpell1.Cast(Game.GetPlayer(), Game.GetPlayer()) debug.notification(Success) TG05BlackFrame.Remove() EndIf EndIf EndEvent
Пример того, что будет, если бадью использует не вампир
UPD: обновил скрипт. Добавил новые анимации, кастомные звуки и изменил затемнение экрана.
Сообщение отредактировал GOLDEN_KINDER: 28 января 2022 - 07:44
#51
Отправлено
Скачивание файла в игре в папку мода. Необходимо 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: 29 июля 2023 - 21:42
#52
Отправлено
Попытка реализации классов прям как в 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
#53
Отправлено
Скрипт переноса зачарования. Работает с 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: 28 июня 2025 - 20:06
#54
Отправлено
Скрипт для снятия с вещей статуса краденного. Вешается на кнопку/рычаг, очищает вещи из контейнера.
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
Темы с аналогичным тегами papyrus, collection, скрипты, готовые решения, моддинг
Моддинг →
Моддинг Oblivion →
Как удалить расы добавленные модами?Автор ktim816, 11 апр 2025 ![]() |
|
![]() |
||
Моддинг →
Моддинг Oblivion →
Скрипт Для СнаряженияАвтор БесездаБойчик, 07 сен 2022 ![]() |
|
![]() |
||
Моддинг →
Моддинг Skyrim →
Заказ на изменение домаАвтор Антенна связи с космосом, 20 апр 2022 ![]() |
|
![]() |
||
Моддинг →
Моддинг Fallout →
Мастерская Fallout 4 →
Не могу найти файл TESV_Papyrus_Flags.flgАвтор Bombero_77, 27 мар 2022 ![]() |
|
![]() |
||
Моддинг →
Моддинг Skyrim →
Попытка создания квеста. Требуется помощь...Автор Гадюка Демона, 23 фев 2021 ![]() |
|
![]() |
Количество пользователей, читающих эту тему: 3
0 пользователей, 3 гостей, 0 скрытых