Перейти к содержимому


Фотография

Каталог готовых скриптов

papyrus collection скрипты готовые решения моддинг

  • Авторизуйтесь для ответа в теме

#41 Ссылка на это сообщение Potatoider

Potatoider
  • Знаменитый оратор


  • 4 350 сообщений
  •    

Отправлено

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

Если скрипт не Ваш (был написан для Вас когда-то в прошлом), указывайте пожалуйста автора.






P.S. Если скрипт не рабочий, Вы пишите об этом здесь. (Только вы должны удостовериться, что скрипт действительно не работает). Далее приводим его в рабочее состояние. В теме соблюдаем чистоту.

P.P.S Оптимизация кода - важный элемент. Если Вы можете оптимизировать работу скрипта, сделайте это и выложите здесь. Исходный скрипт будет обновлен.




  • Авторизуйтесь для ответа в теме
Сообщений в теме: 52

#42 Ссылка на это сообщение angel-deff

angel-deff
  • Авантюрист
  • 173 сообщений
  •  

Отправлено

Если тема для скайрима хнаете рабочий скрипт "закрыть контейнер"? Чтобы он сам закрывался через 2-3 часа. Для прокачки навыка взлома. Мне выслали простой скрипт но KC не хочет компелировать его



#43 Ссылка на это сообщение ac97

ac97
  • Скиталец
  • 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 Ссылка на это сообщение ac97

ac97
  • Скиталец
  • 43 сообщений

Отправлено

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 Ссылка на это сообщение Meridiano

Meridiano
  • Профи

  • 477 сообщений
  •    

Отправлено

Перевод из Dec в Hex (Int в String, пример: 45678 ➔ "B26E"):
 
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 Ссылка на это сообщение Meridiano

Meridiano
  • Профи

  • 477 сообщений
  •    

Отправлено

Создание новой консольной команды средствами Papyrus (требуется SKSE) с примером.

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 Ссылка на это сообщение Meridiano

Meridiano
  • Профи

  • 477 сообщений
  •    

Отправлено

Когда в 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]

————————————
don't forget your falls
————————————


#48 Ссылка на это сообщение ac97

ac97
  • Скиталец
  • 43 сообщений

Отправлено

Когда в 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 Ссылка на это сообщение GOLDEN_KINDER

GOLDEN_KINDER
  • Авантюрист
  • 157 сообщений
  •  

Отправлено

Раздевает и одевает ГГ по триггеру... Если что лишнее, буду рад замечаниям...

 

Scriptname aaaUnequip extends ObjectReference 

Import Game
Import Utility
Import Debug
Import Math

Formlist Property frmList auto

Event OnTriggerEnter(ObjectReference akActionRef)

if(akActionRef == Game.GetPlayer())
  actor who = akActionRef as actor
  frmList.Revert()
  UnequipWeaponActor(who)
  UnequipItemActor(who)
endif

EndEvent

EVENT  OnTriggerLeave (objectReference akActionRef)

If akActionRef == Game.GetPlayer()
  actor who = akActionRef as actor
  EquipItemActor(who)
EndIf
EndEvent

Function UnequipItemActor(Actor target)
    int index
    int slotsChecked
    slotsChecked += 0x00100000
    slotsChecked += 0x00200000 ; игнорировать зарезервированные слоты
    slotsChecked += 0x80000000

    int 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
EndFunction

Function 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()
EndFunction

Function 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

 

зы... нужно в ск формлист создать пустой и подключить к скриптуб, и прошу не тыкать пальцем с усмешкой. это мой первый скрипт :crazy:

Решил опробовать скрипт, но словил ошибки компиляции



#50 Ссылка на это сообщение GOLDEN_KINDER

GOLDEN_KINDER
  • Авантюрист
  • 157 сообщений
  •  

Отправлено

Скрипт для ванны/бассейна/бадьи и т.д. Предназначен для вампиров. Если человек будет использовать, то проиграется только сообщение с отвращением и анимация.

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 Ссылка на это сообщение ac97

ac97
  • Скиталец
  • 43 сообщений

Отправлено

Скачивание файла в игре в папку мода. Необходимо 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 Ссылка на это сообщение ac97

ac97
  • Скиталец
  • 43 сообщений

Отправлено

Попытка реализации классов прям как в 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 Ссылка на это сообщение begemot1451

begemot1451
  • Новенький
  • 8 сообщений

Отправлено

Скрипт переноса зачарования. Работает с 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 Ссылка на это сообщение begemot1451

begemot1451
  • Новенький
  • 8 сообщений

Отправлено

Скрипт для снятия с вещей статуса краденного. Вешается на кнопку/рычаг, очищает вещи из контейнера.
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, скрипты, готовые решения, моддинг

Количество пользователей, читающих эту тему: 3

0 пользователей, 3 гостей, 0 скрытых