Собираем рабочие скрипты здесь, большие и малые, легкие и сложные (Новичкам всё трудно). К скрипту прилагаем описание работы. Скрипты оформлять доступно, можно с построчными комментариями. На один пост - один скрипт (Позже, когда тема разрастется, будет сделана навигация по теме с быстрым переходом к постам)
Если скрипт не Ваш (был написан для Вас когда-то в прошлом), указывайте пожалуйста автора.
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 |
|
|
Количество пользователей, читающих эту тему: 2
0 пользователей, 2 гостей, 0 скрытых






