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

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

Опубликовано
17.10.2021 08:02:31, Ed101 сказал(-а):
Вот пример. Создаю новый объект-подсвечник. Вешаю скрипт на  него, размещаю в ячейке. Активирую, и в консоли будет 0, а не 5.

Задан неверный формат. Попробуй дебажить так: PrintToConsole "Значение - %g" a. Скорее всего, там все ок с назначением переменных, просто консоль не то значение выводится.
Сам по себе блок OnLoad срабатывает отлично в случае, если ты через PlaceAtMe размещаешь объект или же сам объект, на котором висит скрипт, впервые загружается в ячейке. Важно, чтобы тебя в ней не было на момент его появления там. Данный блок не всегда работает так, как хочется.
Как инициализатор, можно использовать условие-ограничитель типа:

Short sLoad

Begin GameMode
if (sLoad == 0)
   Let sLoad := 5
   Return
Endif
End

Begin OnActivate
   PrintToConsole "Значение - %g" sLoad
End

Ничто не истинно, все потрачено

Опубликовано

@Ed101, дружище, а мы с тобой по другому можем сделать) Раз нельзя отключить дочерний источник света без отключения родителя, его ведь всегда можно перенести за пределы ячейки с помощью SetPos и обновить его координаты через Update3D)
А есть еще один вариант - с помощью OBSE-функций управлять самим источником света, в нужный момент загоняя радиус свечения в 0, что должно полностью его отключить. Но тут есть несколько проблем, одна из которых - отсутствие сохранения внесенных изменений в сейв игры, как и возврат в исходное. Это еще +геморрой и лишний код.

Ничто не истинно, все потрачено

Опубликовано (изменено)
17.10.2021 08:41:47, Takirell сказал(-а):

@Ed101, дружище, а мы с тобой по другому можем сделать) Раз нельзя отключить дочерний источник света без отключения родителя, его ведь всегда можно перенести за пределы ячейки с помощью SetPos и обновить его координаты через Update3D)
А есть еще один вариант - с помощью OBSE-функций управлять самим источником света, в нужный момент загоняя радиус свечения в 0, что должно полностью его отключить. Но тут есть несколько проблем, одна из которых - отсутствие сохранения внесенных изменений в сейв игры, как и возврат в исходное. Это еще +геморрой и лишний код.

Ты предлагаешь убирать его в -30000 по оси Z, например?


Кстати да, с сейвами беда. Я не знаю всех данных, что хранятся в сейве. Enabled/Disabled точно есть.

Изменено пользователем Ed101
Опубликовано
17.10.2021 08:47:13, Ed101 сказал(-а):
Ты предлагаешь убирать его в -30000 по оси Z, например?

Как вариант. И возвращать на исходные координаты, когда это необходимо. Проверить стоит, дело может выгореть)

Ничто не истинно, все потрачено

Опубликовано
17.10.2021 08:49:12, Ed101 сказал(-а):
Кстати да, с сейвами беда. Я не знаю всех данных, что хранятся в сейве. Enabled/Disabled точно есть.

Практически все, что могут менять OBSE-функции (имена, пути к моделям\текстурам, какие-то параметры освещения\погоды\рас, шейдера и так далее) - все это не хранится в сейвах и требует возвращения значений на исходные. НО! Это не применимо к новым базовым объектам, созданных функцией CloneForm. Ну и CreateFullActorCopy. Иными словами, в редакторе и в плагинах нет объектов, созданных скриптом, они существуют только в сохранениях, как динамические объекты. Следовательно - игре просто неоткуда взять какие-то исходные параметры объекта из того же мастер-файла, т.к объекта в нем просто нет.
Но тут стоит понимать, что если установлен плагин EngineBugFixes, то все объекты, созданные функцией CloneForm будут удалены в случае, если они не задействованы (не находятся в мире\контейнере\инвентаре игрока\или не используются в данный момент где-либо).

Ничто не истинно, все потрачено

Опубликовано
17.10.2021 08:49:21, Takirell сказал(-а):
Как вариант. И возвращать на исходные координаты, когда это необходимо. Проверить стоит, дело может выгореть)

Ну что, работает твой вариант. Сразу видно опытного скриптера) Мне в Unity так изощраться не приходилось.

ref current;
ref children;

begin onLoad
set current to this;
set children to current.GetNthChildRef 0;

if (children.GetPos z <= -3000)
  current.RemoveFlames
else
  current.AddFlames;
endif
children.Update3D;
end

begin OnActivate
set current to this;
set children to current.GetNthChildRef 0;

if (children.GetPos z <= -3000)
  current.AddFlames;
  children.setPos z, -90;
else
  current.RemoveFlames;
  children.setPos z, -30000;
endif
children.Update3D;
end

 

Опубликовано
17.10.2021 09:36:44, Ed101 сказал(-а):
Ну что, работает твой вариант.

Хмм... скажи, а какую модель ты используешь в качестве подсвечника? Лучше EDID дай, я у себя тоже сделаю и чуть доработаю твой вариант скрипта.

Ничто не истинно, все потрачено

Опубликовано (изменено)
17.10.2021 09:45:06, Takirell сказал(-а):
а какую модель ты используешь в качестве подсвечника?

middlecandlestickfloor04fake.nif

Такую же модель, только со светом (не fake) использует CandlestickFloor04Orange512, например.

Изменено пользователем Ed101
Опубликовано
17.10.2021 10:00:07, Ed101 сказал(-а):
Chandelier04Fake.NIF

Благодарочка, ща у себя намучу и скину свой вариант скрипта.

Ничто не истинно, все потрачено

Опубликовано (изменено)
17.10.2021 10:00:53, Takirell сказал(-а):
Благодарочка, ща у себя намучу и скину свой вариант скрипта.

Перечитай сообщение, я исправил модель. Хотя это не принципиально, какая именно модель, главное чтобы была приписка fake. У них есть огни, но сами по себе они не излучают свет.

Изменено пользователем Ed101
Опубликовано
17.10.2021 10:03:45, Ed101 сказал(-а):

Перечитай сообщение, я исправил модель. Хотя это не принципиально, какая именно модель, главное чтобы была приписка fake. У них есть огни, но сами по себе они не излучают свет.

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

Ничто не истинно, все потрачено

Опубликовано

@Ed101, Короче, наколдовал я такое универсальное дрыгало:

scn TestCandleScript

Short sLoad
Float fDefPos
Float fNewPos
Ref rFlame

Begin OnActivate
if (sLoad > 0)
  if (sLoad == 1)
   rFlame.SetPos z fNewPos
   RemoveFlames
   Let sLoad := 2
  Else
   rFlame.SetPos z fDefPos
   AddFlames
   Let sLoad := 1
  Endif
  rFlame.Update3D
Endif
Return
End

Begin GameMode
;Инициализация
if (sLoad == 0)
  if (IsFormValid rFlame == 0)
   Let rFlame := GetNthChildRef 0
   Return
  Else
   Let fDefPos := rFlame.GetStartingPos z
   Let fNewPos := (fDefPos - 30000)
   Let sLoad := 1
   Return
  Endif
Endif

;Авто-фикс позиций и огней
if ((GetGameLoaded || GetGameRestarted) && sLoad > 0)
  if (sLoad == 1)
   rFlame.SetPos z fDefPos
   if (HasFlames == 0)
    AddFlames
   Endif
  Elseif (sLoad == 2)
   rFlame.SetPos z fNewPos
   if (HasFlames > 0)
    RemoveFlames
   Endif
  Endif
  rFlame.Update3D
  Return
Endif
End 

Блок с авто-фиксом огней можно и убрать, в принципе, только вот если без него отключить огни и сразу же загрузится на сейв, где они включены - огней не будет. Приходится вручную перетыкивать) Убрал еще вообще блок OnLoad, т.к он не всегда выполняется корректно и тогда, когда это нужно. Ну и снес Ref-указатель на сам подсвечник, он банально не нужен и может вообще путать игру.

  • Нравится 1

Ничто не истинно, все потрачено

Опубликовано
17.10.2021 10:51:46, Takirell сказал(-а):
Ed101, Короче, наколдовал я такое универсальное дрыгало:

Неплохо он так оброс. Но я, правда, надеялся, что обойдется без onGameMode, чтобы он постоянно не обрабатывался.

Опубликовано
17.10.2021 11:04:01, Ed101 сказал(-а):

Неплохо он так оброс. Но я, правда, надеялся, что обойдется без onGameMode, чтобы он постоянно не обрабатывался.

Можешь по аналогии переформатировать и без него, но тогда могут быть (и будут) косяки, о которых я писал выше. Просто эта чудесная игра не может нормально работать и вечно приходится костылить даже в, казалось бы, элементарных вещах.
Это нормально написанный скрипт и игру грузить не будет, уж поверь. Игра больше будет лагать из-за источников света, чем от скриптов.

  • Нравится 1

Ничто не истинно, все потрачено

Опубликовано (изменено)
17.10.2021 11:06:54, Takirell сказал(-а):
Игра больше будет лагать из-за источников света, чем от скриптов.

Тут да, согласен. Хорошо, теперь надо решить вторую проблему)

В комнате есть общий выключатель. Сейчас в скрипте на каждый светильник и свет отдельная запись. Цель та же)

Полагаю, надо задействовать массивы.

Изменено пользователем Ed101
Опубликовано
17.10.2021 11:37:02, Ed101 сказал(-а):
Полагаю, надо задействовать массивы.

Зачем? Я чуть покумекаю и рожу готовый вариант, есть пара мыслей.

  • Нравится 1

Ничто не истинно, все потрачено

Опубликовано

Итого, что у меня получилося... Основной универсальный скрипт светильников был дополнен и чуть оптимизирован, теперь это чудовище выглядит вот так:

scn TestCandleScript

Short sLoad
Short sValue
Short sSwitch
Float fDefPos
Float fNewPos
Ref rSwitch
Ref rFlame

Begin OnActivate
if (sLoad > 0)
  if (IsActionRef rSwitch == 0)
   if (sLoad == 1)
    Let sLoad := 2
   Else
    Let sLoad := 1
   Endif
   Let sSwitch := 1
  Else
   ;Т.к команда об активации была получена от основного рубильника, нам нужно понять - в каком именно положении он находится. Для этого считываем у него переменную sFlag
   Let sValue := rSwitch.GetVariable "sFlag"
   if (sValue == 0) && (sLoad != 2)
    Let sSwitch := 1
    Let sLoad := 2
   Elseif (sValue == 1) && (sLoad != 1)
    Let sSwitch := 1
    Let sLoad := 1
   Endif
  Endif
Endif
Return
End

Begin GameMode
;Инициализация
if (sLoad == 0)
  if (IsFormValid rFlame == 0)
   Let rFlame := GetNthChildRef 0
   Return
  Else
   Let fDefPos := rFlame.GetStartingPos z
   Let fNewPos := (fDefPos - 30000)
   Let sLoad := 1
   Return
  Endif
Else
  ;Инициализируем выключатель
  if (IsFormValid rSwitch == 0)
   Let rSwitch := GetParentRef
   Return
  Endif
  ;Блок, отвечающий за включение\выключение огня и света (объединенный)
  if (sSwitch > 0)
   if (sLoad == 1)
    rFlame.SetPos z fDefPos
    if (HasFlames == 0)
     AddFlames
    Endif
   Elseif (sLoad == 2)
    rFlame.SetPos z fNewPos
    if (HasFlames > 0)
     RemoveFlames
    Endif
   Endif
   rFlame.Update3D
   Let sSwitch := 0
   Return
  Endif
Endif

;Авто-фикс позиций и огней
if ((GetGameLoaded || GetGameRestarted) && sLoad > 0)
  Let sSwitch := 1
  Return
Endif
End

А вот скрипт на выключателе (я использовал модельку рычага с EDID RFSwitchLever01):

scn TestLightSwitchScript

Short sCount
Short sFlag
Ref rChild
Ref rMe

Begin OnActivate
if (IsAnimPlaying == 0)
  if (sFlag == 0)
   PlayGroup Forward, 1
   Let sFlag := 1
  Else
   PlayGroup Backward, 1
   Let sFlag := 0
  Endif
  ;Находим и активируем все дочерние светильники, привязанные к этому рычагу
  if (IsFormValid rMe == 0)
   Let rMe := GetSelf
  Endif
  Let sCount := GetNumChildRefs
  while (sCount >= 0)
   Let sCount -= 1
   Let rChild := GetNthChildRef sCount
   ;На всякий случай пропускаем "битые" ссылки (если они есть)
   if (IsFormValid rChild == 0) || (IsRefDeleted rChild)
    continue
   Endif
   rChild.Activate rMe, 1
  loop
  Return
Endif
End

Собсна, чтобы все это работало, нужно разместить нужное кол-во светильников в помещении и каждый из них привязать через ParentRef к рычагу. Все остальное самостоятельно схватится и должно работать. Само собой, каждый светильник можно включать\выключать по желанию, вне зависимости от положения главного рубильника.

P.S Есть еще парочка вариантов реализации задумки, но, как мне кажется, что приведенный выше метод - наиболее прост в исполнении. Ну, как по мне :D

  • Нравится 2

Ничто не истинно, все потрачено

Опубликовано
17.10.2021 13:06:25, Takirell сказал(-а):
P.S Есть еще парочка вариантов реализации задумки, но, как мне кажется, что приведенный выше метод - наиболее прост в исполнении. Ну, как по мне :D

Сейчас затестим.

Опубликовано
17.10.2021 13:06:25, Takirell сказал(-а):
P.S Есть еще парочка вариантов реализации задумки, но, как мне кажется, что приведенный выше метод - наиболее прост в исполнении. Ну, как по мне :D

Не совсем идеально, но работает хорошо. Для моих целей более чем достаточно.

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

Опубликовано
17.10.2021 14:31:20, Ed101 сказал(-а):

Не совсем идеально, но работает хорошо. Для моих целей более чем достаточно.

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

Да, я знаю об этом. Просто нужно переменные авто-обновлять в зависимости от статуса всех светильников. Мб позже я подумаю, как это сделать.

Ничто не истинно, все потрачено

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

Еще немного доработал скрипт. Но это, скорее, для моих нужд.

Begin OnActivate
	if (IsActionRef Player // поставил проверку на запуск от игрока
		if (IsFormValid rMe == 0)
			Let rMe := GetSelf
		Endif
		
		Let sCount := GetNumChildRefs
		
		while (sCount > 0)// было >= 0, поэтому была лишняя проверка с индексом -1. Ошибка ловится, но зачем, когда можно избежать
			Let sCount -= 1
			Let rChild := GetNthChildRef sCount
			
			if (IsFormValid rChild == 0) || (IsRefDeleted rChild)
				continue
			Endif
			
			rChild.Activate rMe, 1
		loop

                ; Перенес в конец, т.к. изначально весь свет включен и рубильник срабатывал со второго раза.
                ; Убрал анимацию, просто не нужна.
		if (sFlag == 0)
			Let sFlag := 1
		Else
			Let sFlag := 0
		Endif

		Return
	Endif
End
Изменено пользователем Ed101
  • Нравится 2
  • 3 недели спустя...
Опубликовано

Можно ли переориентировать по сторонам света ранее загруженную внутреннюю ячейку? К примеру я могу задать Reference для NorthMarker'а, а затем через скрипт и команду SerAngle Z изменить его положение. Но в результате изменится только отображение ячейки на миникарте, при этом маркеры дверей останутся на прежнем месте, а показания компаса и соответственно положение маркера игрока на карте никак не поменяются. Команда ResetInterior не помогает.

Опубликовано
09.11.2021 07:38:16, Pimple03 сказал(-а):
Можно ли переориентировать по сторонам света ранее загруженную внутреннюю ячейку?

Так ведь в каждой ячейке есть компас-маркер.

Опубликовано
09.11.2021 08:37:47, Bianor сказал(-а):
Так ведь в каждой ячейке есть компас-маркер.

Маркер то есть, но манипуляции с ним ничего кроме перечисленного выше не дают, если ячейка уже была однажды загружена.

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

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

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

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

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

Войти

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

Войти
×
×
  • Создать...