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

Тонкости скриптов


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

Приступим, пожалуй. Думаю все скриптеры знают, что язык ТЕС3 далек от совершенства и таит в себе множество подводных камней. И чтобы не споткнуться о них - я решил создать эту тему.

 

1. Количество переменных. Ну их может быть очень много, однако подвох есть и здесь. Это 34 переменная одного типа (short, float, long - неважно). Она зачастую принимает неверные и странные значения, так что если ваш скрипт использует много переменных - не используйте 34 по счету. По объяснению cdcooley на оф.форуме это происходит из-за того, что ASCII код 34 символа - кавычка и именно она часто записывается в переменную вместо нужного значения.

 

2. Очередность исполнения скриптов. Все скрипты ставятся в очередь по мере их появления, однако если в скрипте используется команда Startscript, чтобы запустить новый глобальный скрипт, то вся очередь сбрасывается на начало и прогоняется еще раз. Подробнее об этом можно почитать на оф.форуме в этом посте

Здесь приведу краткий перевод:

Имеем:

1 локальный объект A со скриптом

1 самозавершающийся глоб.скрипт B

1 самозавершающийся глоб.скрипт C

1 всегда работающий глоб.скрипт D

 

Что должно быть:

1. A работает и стартует скрипт  B

2. D работает

3. B работает и стартует скрипт C

4. C работает

 

Что, я думаю, происходит на самом деле:

1. A работает и запускает скрипт B

2. D работает

3. B работает и запускает скрипт C

4. D работает

5. C работает

 

или что-то в этом роде. Я предполагаю, что использование startscript заставляет Морроувинд заново проработать список глоб.скриптов, включая те, что уже работали ранее.

 

Graphite posted, 07/16/04 03:25 AM

 

Я думал, совпадают ли виденные мной результаты с тем, как ты предполагаешь это работает и решил провести тест. Я создал 2 глоб.переменных с названиями  test_global и test_local. Затем написал следующие 4 скрипта:

 

 

begin script_A

short state
set test_local to test_local + 1

if ( state == 1 )
startScript "script_B"
set state to 0
endif

end

 

begin script_B

stopScript "script_B"
startScript "script_C"

end

 

begin script_C

stopScript "script_C"

end

 

begin script_D

short temp
set test_global to test_global + 1
set temp to test_global - test_local
MessageBox "counter-difference: %g " temp

end

 

Script D был добавлен в стартовые скрипты. Script A был приаттачен к контейнеру и помещен в игру. Теперь получалось, что script A увеличивает "local" счетчик, а  script D увеличивает "global" счетчик перед тем, как показать разницу между ними.

Теперь, если мое предположение верно, разница останется постоянной, т.к. script A работает также часто, как script D. Если верно мое наблюдение, то это значение будет меняться каждый раз, как я меняю значение переменной state на 1, потому что script D будет работать чаще, чем script A.

 

Я вошел в игру и получил:

 

counter-difference: 0

counter-difference: 0

counter-difference: 0

 

Кажется все нормально... оба скрипта заработали водно и то же время. Я открыл консоль, выбрал ящик и ввел "set state to 1".

 

counter-difference: 2

counter-difference: 2

counter-difference: 2

 

Сделал это еще раз:

 

counter-difference: 4

counter-difference: 4

counter-difference: 4

 

Это указывает на то, что script D работает дважды всякий раз, как я меняю state на 1. Еще раз, я считаю, что порядок работы такой  A, D, B, D, C, D, а после снова  A, D, A, D, A, ...

 

3. О работе команд if-endif и if-elseif-endif.

В скриптах часто приходится использовать, так называемые переменные состояния, дабы обеспечить правильную работу скрипта. Обычно такой переменной дается имя state и она постепенно меняется в ходе его работы. И такую проверку организуют либо через группу последовательных if-endif, либо более длинным блоком if-elseif-endif. И из-за этого могут возникнуть проблемы, т.к. во втором случае, если наша контрольная переменная меняется ВНУТРИ блока, то обнаружится ее изменение только в следующем фрейме, т.е. при следующем прогоне скрипта, а не немедленно, что, в некоторых случаях, желательно, а в некоторых, наоборот, может привести к ошибкам. К данному посту приложен файл с плагом, в нем всего 2 скрипта, показывающих данный принцип. Подключите его, в консоли наберите Startscript, Script_A для запуска 2 варианта (if-elseif-endif) - и вы увидите, что счетчик фреимов будет разным для каждого состояния переменной state.

 

Begin Script_A

short state
short framecount

set framecount to ( framecount + 1 )

if ( state == 0 )
  MessageBox "State - %.0f, Frame - %.0f", state, framecount
  set state to 1
elseif ( state == 1 )
  MessageBox "State - %.0f, Frame - %.0f", state, framecount
  set state to 2
elseif (state == 2 )
  MessageBox "State - %.0f, Frame - %.0f", state, framecount
  set state to 0
  StopScript, Script_A
endif

end

 

Запустите аналогично Script_B и вы увидите, что он исполняется за один фрейм, проходя все стадии переменной state.

Begin Script_B

short state
short framecount

set framecount to ( framecount + 1 )

if ( state == 0 )
  MessageBox "State - %.0f, Frame - %.0f", state, framecount
  set state to 1
endif
if ( state == 1 )
  MessageBox "State - %.0f, Frame - %.0f", state, framecount
  set state to 2
endif
if (state == 2 )
  MessageBox "State - %.0f, Frame - %.0f", state, framecount
  set state to 0
  StopScript, Script_B
endif

end

 

-----------------------------------------

Пожалуй все на сегодня. Если Вы также знаете какой-то секрет или возможность скриптов ТЕС3 - поделитесь своими знаниями или предположениями в данной теме.

Изменено пользователем Boblen
Ссылка на комментарий
Поделиться на другие сайты

  • Ответов 335
  • Создана
  • Последний ответ

Топ авторов темы

Топ авторов темы

Изображения в теме

Цитата MSFD: - "Локальные переменные уникальны в пределах данного экземпляра скрипта. То есть одинаковые локальные переменные на разных объектах не влияют друг на друга".

 

Чушь! Еще как влияют друг на друга! Но, надо сказать, что влияют они не всегда, а только если один объект со скриптом в непосредственной близости от другого объекта с другим скриптом, но с теми же переменными! (distance ~ 50-100) Выяснил я это абсолютно случайно, дело было так:№1 на активаторе висит скрипт телепортации. При OnActivate == 1 переменной состояния - "status" присваивается значение = 1, дальше MessageBox, с проверкой GetButtonPressed при нажатии кнопки, отличной от последней, отправляет игрока в различные локации (Экстерьеры). №2 Есть кольцо телепортации в интерьер. При OnPCEquip == 1 переменной состояния тоже "status" также как и в первом скрипте присваивается значение (обратите внимание!) = 1. Как же я был удивлен, когда, отказавшись (предварительно активировав (при отказе status сбрасывался в 0)) от путешествия в экстерьер и, решив отправиться в интерьер, меня перекинуло в ЭКСТЕРЬЕР, причем по счету соответствовавший первой кнопке первого скрипта! (Кольцо также с MessageBox и 2-мя кнопками: "Да" "Нет"), При отказе телепортации в интерьер, я отнюдь не оставался на месте, как хотел того, а перемещался в то место экстерьера, которое соответствовало 2-й кнопке 1-го скрипта! Я решил поэкспериментировать, и обнаружил, что в движке в скриптах главного меню (Сохранить, Выйти, Загрузить и тд), меню закрепления быстрых кнопок для смены оружия, магии и тп, также присутствует переменная, имя которой либо "status" либо "button"!!!Причем в последнем меню, меня телепортировало по всем локациям, при выборе кнопки меню, по счету совпадавшей с 1-м скриптом! Лечилось это 2-мя методами: изменением имен переменных... Хм, удивительно не помогло (возможно, не те переменные менял...) и введением условия "do-once"(сработало отлично!) подобные казусы были обнаружены и с другими скриптами, но поведал я об этом, тк он был первый, и довольно яркий, на мой взгляд.

 

Небольшая поправка: Дистанция роли не играет! Во внимание принимается только активность ячейки и значение одинаковых переменных в разных локальных скриптах!

Изменено пользователем lost81
Ссылка на комментарий
Поделиться на другие сайты

DinkumThinkum

1.  Если скрипт генерирует более, чем одно текстовое сообщение в одном фрейме, то возможен CTD.  Это относится не только к тексту, генерируемому командой  'MessageBox', но также и к сообщениям 'Ваш журнал обновлен, ненерируемых командой 'Journal'. Вот почему мой StartUpScript(из плагина Unarmored Corrector) делает задержку в один фрейм между сообщением '...активирован' и командой  'Journal': у меня несколько раз прохоисходил  CTD при загрузке, огда оба текста демонстрировались в одной фрейме.

 

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

 

2. Если цель нацеленного глобального скрипта не помещена в мир через Construction Set, скрипт будет терять ее каждый раз при перезагрузке игры. Например 'Player' ID реально не расположен в игровом мире, он помещается туда после начала новой игры. Для того, чтобы мой Main

script был нацелен на игрока, StartUpScript останавливает его и перезапускает, правильно нацеливая на 'Player', каждый раз при перезагрузке. /Речь ведется о плагине Unarmored Corrector/

 

3.  Если игрок ведет кулачный бой (Hand-to-Hand) и его руки готовы (т.е. кулаки перед лицом), то одевание или удаление части брони или одежды заставит персонаж на мгновение "дернуться": он возвращается в обычную позицию, руки по бокам, а затем снова в позицию H-to-H. Обычно это незаметно. Однако мой скрипт периодически надевает невидимые шлемы, так что мне пришлось добавить несколько улучшающих таймеров и удостоверится в том, что это будет незаметно.

 

Заметьте, чтоNote #3 это не графический глюк: значение, возвращаемое 'GetWeaponDrawn' становится равным нулю каждый раз, как это происходит.

Это выдержка из редми к плагину Unarmorred_Corrector (сейчас лежит на Саммите, скоро и у нас в базе).

Ссылка на комментарий
Поделиться на другие сайты

  • 3 недели спустя...

GetStat, ModStat and SetStat: A concerned modder’s guide.

Throughout the term “base stat” means the value of the stat when yellow – i.e. unmodified by any in game bonus / penalty apart from fortification abilities.

 

GetStat:

Always returns the current stat – including any bonus / penalty. No nasty side effects as far as I’m aware, so GetStating should always be safe. There is (sadly) no GetBaseStat function. MWSE has these I think, but they don't include e.g. racial fortification abilities in the base (I think), and usually you'd want them included.

Note that all stats are stored as floats, even though they should nearly always be integers. Usually this makes no difference.

 

Most of the problems of ModStat and SetStat explained below are only really important for the player (and companions I guess). These functions won’t do anything worse than screwing up the stats they operate on, so for normal NPCs, there’s not much point worrying about all this. I’ve only tested the following on the player, but I presume the same is true for NPCs.

 

As with pretty much anything in Morrowind modding, if you have a choice to use scripting or something else, then use something else. For ModStat / SetStat, the “something else” will usually be fortify/drain stat spell effects or curses. For most purposes, standard effects will work as well as ModStat and SetStat, and will be much less buggy.

 

ModStat:

Usually increases (or decreases) the stat concerned by the amount given (local variables are accepted). Both the current stat and the base stat are affected. Usually preserves the amount of fortification or damage on the stat.

 

E.g. for a player with strength 50(base) + 10(fortification) = 60(current)

Player->ModStrength 10 will give 60(b.) + 10(f.) = 70(c.), just as you’d expect.

 

Limitations: ModStat can never decrease a stat below zero. It also cannot increase a base stat to a value over 100. Trying to Modstat below zero or above 100 can cause trouble in the following ways:

 

Strength = 30(b.) + 0(f.) = 30(c.)

ModStrength, -50 gives

Strength = 0(b.) + 0(f.) = 0(c.)

ModStrength 50 [hoping to undo the first modstrength]

Strength = 50(b.) + 0(f.) = 50(c.) – and the player has a permanent bonus.

 

You can try to avoid this by instead checking that you don’t reduce the stat by more than the current value, but that won’t always work. For example:

Strength = 40(b.) + 10(f.) = 50(c.)

ModStrength -50

Strength = 0(b.) + 0(f.) = 0(c.)

ModStrength 50

Strength = 50(b.) + 0(f.) = 50(c.) – and the player’s base strength is increased.

If he then removes the fortification, his strength will show up as damaged. Restoring and replacing the forification will leave him with:

Strength = 50(b.) + 10(f.) = 60(c.)

 

It’s never safe to ModStat down by more than the player’s base stat. Given that there’s no failsafe method to determine the player’s base stat, this is annoying [the only ways I know to determine the player’s base stat are the method which I use in GCD – complicated, and doesn’t work correctly when the player’s stat is damaged -, using MWSE, which I think doesn’t include permanent abilities in the base (for most purposes you’d want permanent abilities to count towards the base). Even systematically removing every conceivable bonus / penalty – which is a drag anyway – won’t always work with other scripted mods].

 

Going over 100 has similar problems. The following is fine:

Strength = 70(b.) + 20(f.) = 90(c.)

ModStrength, 20 gives

Strength = 90(b.) + 20(f.) = 110(c.)

ModStrength -20 gives

Strength = 70(b.) + 20(f.) = 90(c.) – all fine.

 

However, this also happens for some reason:

Strength = 70(b.) + 20(f.) = 90(c.)

ModStrength, 50 gives

Strength = 100(b.) + 40(f.) = 140(c.) – already screwed up.

ModStrength -50 gives

Strength = 50(b.) + 40(f.) = 90(c.) – further screwed up.

 

This problem arises because if a stat is fortified or damaged, and the base is not 100, ModStat always increases the current stat by the value you give it, even if the base stops at 100. If the base is 100, ModStating won't have any effect. If the stat is equal to its base value, ModStat will behave normally.

 

So this is fine (so long as you don’t ModStat -50 afterwards):

Strength = 70(b.) + 0(f.) = 70(c.)

ModStrength, 50 gives

Strength = 100(b.) + 0(f.) = 100(c.)

 

And this is fine:

Strength = 100(b.) + 20(f.) = 120(c.)

ModStrength, 50 gives

Strength = 100(b.) + 20(f.) = 120(c.)

 

But this isn’t:

Strength = 99(b.) + 20(f.) = 119(c.)

ModStrength, 50 gives

Strength = 100(b.) + 69(f.) = 169(c.) – oh dear.

 

Of course as a modder you won’t know in general what the Base + Fortification is before you use the ModStat function, so you have no way to compensate for errors even once you know what can go wrong. Joy!

 

Ok, so as long as you never try to ModStat the current stat over 100, everything should be fine, right?

Sadly not:

Strength = 95(b.) - 10(damage) = 85(c.)

ModStrength, 15 gives

Strength = 100(b.) + 0(f.) = 100(c.) – OK so far

ModStrength, -15 gives

Strength = 85(b.) + 0(f.) = 85(c.) – Permanent strength damage.

 

So under what circumstances will ModStating up or down give reliably predictable results?

Only when you know the base value of the stat.

 

Can you reliably work out the base value of the stat?

No – only in some situations is it possible (the process is explained below, and implemented in my Gals_Sk_Acrobatics script in GCD). Even then it’s not easy. (it’s worth checking script extenders for updates though)

 

 

SetStat:

Sets both the base and the current value to the value you give it (also accepts local variables).

 

This will pretty much always cause problems if the player’s current stat is not equal to their base stat. If their stat is fortified, and you SetStat it, it’ll turn yellow at the value you give it. Removing the fortification, then restoring will give the player a permanent bonus.

If their stat is damaged, SetStating it will again turn it yellow, but this time at a lower value than you (probably) intended. They will instantly have their base knocked down to the value you set.

 

Using SetStat is therefore never even slightly safe unless you know the player’s base stat, and compensate accordingly. While you can’t guarantee that ModStat won’t cause trouble, you can almost guarantee that SetStat will.

Using SetStat is therefore almost always a bad decision – if you’re ever not sure whether it’s a bad decision, then it is.

 

 

Then are these functions useless!?

Not always. You can use them on NPCs without worrying too much. Using them on companions could occasionally not have the effect you want, but it’s unlikely the player would notice.

 

Using ModStat on the player can be safe, so long as you’re careful – e.g. to increase strength by (up to) 10 points temporarily, you could:

Give the player a very strong restore strength curse for a frame or two. (you can then be sure his strength isn’t damaged)

ModStrength by MIN{ 10, 100-current }

ModStrength down by the same amount when you want the effect to finish.

 

You can never be sure that giving a temporary penalty won’t cause trouble, but if you only reduce the stat by at most 30, then it’ll usually be fine since most players start with all stats that high. Restoring the stat after you’ve reduced it like this could cause trouble if the player has since gained base stat points, and his stat started close to 100.

 

 

Some "cunning" tricks with SetStat / ModStat:

WARNING – using the following tricks might cause even more trouble than using the functions normally. Use with care. Conflicts are likely.

 

Finding the base of a stat:

You can find the base of a stat using the (mis)behaviour of ModStat, as follows:

(1)Make sure that the player’s stat isn’t damaged [You have been tracking increases in the natural values of the stat since the beginning of the game, haven’t you? If you haven’t, then you have no way of knowing if it’s damaged – you could check the base value on installation of your mod, so long as you ask the player to install when stats aren’t damaged / fortified].

(2)If it is damaged, give up. (you might want to check script extenders)

(3)If it isn’t:

(4)Store the current value of the stat.

(5)Mod the stat up to 100 if it isn’t already 100 or more.

(6)ModStat, 1 as many times as you can while the stat still increases.

(7)The fortified part of the stat is the value it reached minus 100.

(8)The base part of the stat is the current value minus the fortified part.

(9)Return the stat to its current value (DON’T use SetStat, use ModStat).

 

Armed with the base value, you can now use ModStat and SetStat wisely and safely, so long as you’re very careful.

 

 

Damaging a stat:

To set a stat to e.g. 50 damaged from 70, you can do the following:

Player->SetStat, -20 [base and current are now both -20]

Player->ModStat, 0 [Necessary: sets the base to 0]

Player->ModStat, 70 [base = 70, current = 50 (red)]

 

This level of precision is not possible in general using e.g. damage stat curse effects, but it’s not usually necessary either. The above can also be done within one frame, whereas a curse effect might take a second to kick in. Again, the speed can be useful, but is usually unnecessary.

 

Fortifying a stat:

To set a stat to e.g. 120 fortified from 90, you can do the following:

Player->SetStat 130 [base and current are now both 130]

Player->ModStat, 0 [Necessary: sets the base to 100]

Player->ModStat, -10 [base = 90, current = 120 (white)]

 

 

Right, I hope that made some sense. Now you know pretty much everything about the Get/Set/ModStat functions. Just remember not to use them wink.gif.

 

Оригинал здесь

Автор Galsiah

Ссылка на комментарий
Поделиться на другие сайты

I thought it would helpful to make this information public knowledge.

 

The ToggleMenus function can be useful to to force the game engine out of Menu Mode, but some scripters (myself included) have had real issues with using it.

 

Remember that a second ToggleMenus call is always necessary. Without this, menus do not "have permission" to display at all. Attempting to force menus to open by script, while the general Menus state is toggled "off", will often cause freezing/CTD.

 

 

As others have found, however, using a double ToggleMenus call has the nasty side effect of completely disabling the HUD. Once disabled, the HUD will not reappear until it is reinitialized.

 

There are only two events, that I know of, that will force the game engine to reinitialize the HUD without the player's intervention. There may be others, but these are the ones I have tested and which I know work:-

 

 

Cell Load

 

Any new cell load (interior or exterior) forces the game engine to reinitialize the game interface completely, including the HUD.

 

e.g.

 

Begin nigedo_hidemove

If ( OnActivate )
   ToggleMenus
   Player->COE 0 0
   ToggleMenus
Endif

End

 

 

This means that it is entirely safe to use ToggleMenus to hide the cell load progress bar in the case of scripts that teleport the player by means of multiple cell loads. Delaying the second ToggleMenus call until the same frame that the player arrives in their destination cell will hide the transportation and still reinitialize the HUD.

 

 

ForceGreeting

 

This is the other, and more useful, means of reinitializing the HUD.

 

1. If you use ToggleMenus to immediately exit dialogue, you should add follow on code to initiate a ForceGreeting from the same NPC and then call ToggleMenus twice, to restart the HUD and safely leave Menu Mode respectively.

 

e.g.

 

Call this script from a StartScript in the required dialogue Results field:-

 

     Begin nigedo_exit_dialogue

     Short step

     If ( step == 0 )
         ToggleMenus
         ToggleMenus
         Set step to 1

     Elseif ( step == 1 )
         ForceGreeting
         ToggleMenus
         Set step to 2

     Elseif ( step == 2 )
         ToggleMenus
         MenuTest
         StopScript nigedo_exit_dialogue
     Endif

     End

 

 

Notes:

* The functions must be called in separate frames in this order to work successfully.

* Calling ForceGreeting in the same frame as the first of the second set of ToggleMenus calls (step 1), allows the HUD to remain active despite menus state being toggled "off". I believe this is because the ForceGreeting is already in the process of reinitializing the HUD as the ToggleMenus call processes. The ToggleMenus call catches the dialogue window, but not the HUD.

* The MenuTest call (step 2) eliminates an inventory view Menu Mode state that appears to underlie dialogue Menu Mode states.

 

 

2. If you want to use this method to safely exit Menu Mode states other than dialogue, you will need to create a custom NPC that you can use to initiate a ForceGreeting call, as required.

 

To do this:

* Create a new race with default attributes - call it "race_invisible"

* Create a new NPC using the race "race_invisible" and call him "npc_HUD_reset"

* Create a new dialogue entry towards the start of the "Greetings 0" section. Filter it by ID = "npc_HUD_reset" and enter the text "." (this isn't strictly necessary, but it's cleaner)

 

Then add this script to "npc_HUD_reset":-

 

 

      Begin nigedo_reset_HUD

     Short step

     If ( GetDisabled )
         SetDelete 1
         Return
     Endif

     If ( step == 0 )
         ForceGreeting
         ToggleMenus
         Set step to 1

     Elseif ( step == 1 )
         ToggleMenus
         MenuTest
         Disable
         Set step to 0

     Endif

     End

 

 

Now, whenever you create a script that uses ToggleMenus calls to exit Menu Mode, add a follow on section that places an instance of "npc_HUD_reset" at the player.

 

e.g. This example exits the inventory share Menu Mode state, when activating a container:-

 

      Begin nigedo_container_shutDown

     Short step

     If ( step == 0 )
         If ( OnActivate )
              Activate
              Set step to 1
         Endif

     Elseif ( step == 1 )
         MenuTest
         ToggleMenus
         ToggleMenus
         Set step to 2

     Elseif ( step == 2 )
         If ( MenuMode )
              Return
         Endif
         PlaceAtPC npc_HUD_reset 1 0 0
         Set step to 0
     Endif

     End

 

 

Note that, in this case, a MenuTest call is necessary at step 1, in order to exit an underlying inventory view Menu Mode state. This is not always necessary and MenuTest can cause problems if called unnecessarily. Experiment with your specific needs and determine whether you may need additional MenuTest calls to assist the process. smile.gif

 

Оригинал здесь

Ссылка на комментарий
Поделиться на другие сайты

Ссылка на комментарий
Поделиться на другие сайты

  • 5 месяцев спустя...

Ты MSFD читал? Move двигает по относительным координатам, а doonce вообще не команда, а переменная, которую часто используют моддеры для того, чтобы структурировать скрипт...

 

ЗЫ: Это не та тема, где нужно задавать эти вопросы.

Ссылка на комментарий
Поделиться на другие сайты

  • 3 месяца спустя...

Мне не встречалось в руководстве упоминание о таком нюансе, но я сама так пару раз попадала:

 

Кажется вроде бы удобно писать новый скрипт на базе уже существующего, вызвав его сразу через окно параметров объекта вместо того, чтобы копаться в списке скриптов. Однако, по неизвестной причине, даже если у нового скрипта совершенно другое имя, после нажатия на save новый скрипт перепишет существующий, и тот пропадет безвозвратно, даже если скрипт был стандартный, типа nolore. Тоже самое произойдет при попытке и просто писать новый скрипт в окне существующего. :1anim_am:

Это исправить можно только выйдя из редактора без сохранения, либо удалить новый скрипт в tesame, что в любом случае означает - работа кагути под хвост :1anim_ac:

Ссылка на комментарий
Поделиться на другие сайты

  • 1 год спустя...
Функция PlaceItem работает коряво. Она всегда ставит ПОДБИРАЕМУЮ версию предмета. Если это была одежда или оружие или что-то что можна подобрать - то всё ОК. Но если плейсить статики, активаторы, непереносимые светильники - всё то, что нельзя подобрать - то появляются глюки. При наведении прицела на призванный объект появляется его ИДшник (исключение - активатор с заданным именем) и при активации он попадет в инвентарь. При попытке просмотра инвентаря Морра зависнет, ибо такие характеристики как вес, цена, иконка итд. не то чтобы не заданы - их вообще НЕТ. Единственное исключение - если разместить PlaceItem`ом активатор со скриптом, который отлавливает активацию, то таких глюков не будет - он активируется, как положено. Тоже должно сработать и для не переносного светильника со скриптом, однако имени у него нет и отобразится ИД...
Ссылка на комментарий
Поделиться на другие сайты

  • 7 месяцев спустя...

1) Что такое "the HUD"?

это все дополнительные элементы на экране, полоски здоровья, иконки заклинаний, крестик прицела

 

2) Функция setscale, добавляемая Трибуналом, не воспринимает значения меньше 0.01.

3) if...else...endif могут быть вложены друг в друга не более 10 раз.

Ссылка на комментарий
Поделиться на другие сайты

1) HUD - Heads Up Display - То что видит геймер играя в игру. Типа Полоска здоровья, прицел итд. :-)

2) Она также не воспринимает значения больше 10 (это есть в МСФД).... хотя.... там нижняя граница 0, а не 0.01... впрочем, врядли это так страшно... :-)

3) интересно.... в МСФД только про максимальное количество и расстояние между блоками, а по вложенность нет :-)

Ссылка на комментарий
Поделиться на другие сайты

1) HUD - Heads Up Display - То что видит геймер играя в игру. Типа Полоска здоровья, прицел итд. :-)

2) Она также не воспринимает значения больше 10 (это есть в МСФД).... хотя.... там нижняя граница 0, а не 0.01... впрочем, врядли это так страшно... :-)

3) интересно.... в МСФД только про максимальное количество и расстояние между блоками, а по вложенность нет :-)

1) Здорово, спс:-)

 

2) По крайней мере 0.009 и меньше - это то же самое, что и 0.01. Я пытался в 1000 раз уменьшить кантон в Вивеке, чтобы поместить его на мини-карту... а он максимум стал высотой с Игрока. Или даже двух:-)

 

3) Компилер так и говорит:

"Script ...

Max nesting of 10 exceded on line ..." :-)

Пришлось применить отрицание ("И" переделывает в "ИЛИ"!) и вместо else ставить return'ы.

 

4) Если команду SetScale "size" ставить после вызова/применения заклинания, то обычно она не срабатывает. Я думаю, это потому, что применение/снятие эффекта занимает много времени - и скрипт сбрасывается (виснет и начинается сначала), поэтому я либо ставлю ее ДО, либо изменяю локальную переменную status и работаю с ней в следующем фрейме.

 

5) И последнее (это меня убило). Оказывается команда StopScript "CurrentScript" не прекращает выполнение текущего скрипта, как можно подумать, а ПО-МОЕМУ только активизирует флаг о его завершении. И когда исполнение дойдет до строчки "end", скрипт выгружается из памяти. Пример из "Необходимостей Морровинда" (глобальный скрипт):

Begin BINN_start_message

short DaysLeft

if ( BINN_message == 1 )
StopScript "BINN_start_message"; я-то думал, здесь конец
set BINN_message to 0; ан нет
return; идем вканец
endif

...

end; и вот здесь завершаем выполнение

 

НО! Если ПОСЛЕ StopScript "CurrentScript" написать StartScript "SomeScript", то скрипт SomeScript не запустится! StartScript надо писать ПЕРЕД завершением текущего скрипта! Шо за бред??? КАК ЭТО РАБОТАЕТ???

 

6) ВНИМАНИЕ! ОПАСНОСТЬ! Компилер не проверяет (по крайней мере, у меня; версия Трибунал), объявлены ли локальные переменные, используемые в скрипте, поэтому при операции над необъявленной переменной скрипт перестает работать! Если переменных много, за этим надо строго следить.

Изменено пользователем boeny
Ссылка на комментарий
Поделиться на другие сайты

  • 1 год спустя...

Я выяснил две вещи. Я, конечно, уже писал об этом на этом форуме, но боюсь меня не правильно поняли, поэтому повторюсь

1) скрипт с xAITravel должен выглядеть примерно так:

 

begin kKirStartNPCKiss

 

short kislong

short kirtravelscrp

float Player_X

float Player_Y

float Player_Z

 

if ( kirtravelscrp == 0)

if ( kirtravelscrp == 0)

set kirtravelscrp to 1

set Player_X to Player -> GetPos, X

set Player_Y to Player -> GetPos, Y

set Player_Z to Player -> GetPos, Z

xaitravel Player_X Player_Y Player_Z

set kislong to 1

set kislong to 2

startscript Kir_Romance_Kiss

elseif ( kislong < kislong )

if ( kislong == 9)

set kislong to 1

endif

endif

endif

end

 

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

 

2) баг PositionCell, описанный в Morrowind_Scripting_for_Dummies_8.0_Rus

Цитата:

А также: если вы пытаетесь телепортировать NPC из ячейки, где игрок никогда не был (соответственно ни разу не видел этого NPC), туда, где игрок находится в данный момент, то при попытке поговорить с этим NPC Морр вылетит. (Прим. Gwathlobal)

Решение:

В MWEdit в разделе NPC выбираете какого-нибудь непися и делаете "Create copy". в поле "new id" пишите другой ид и сохраняете. в TES Construction Set эту копию помещаете в какую-нибудь ячейку и всё! Можно использовать PositionCell или xPositionCell с этой копией! игра не вылетит!

Изменено пользователем Ллирик
Ссылка на комментарий
Поделиться на другие сайты

  • 3 года спустя...

Итак, после многих лет игнорирования сией темы я таки решил испытать скрипты.

 

И вот что у меня не получается:

есть вот такая конструкция

Set PC_Personal to ( Player->GetPersonality )

PC_Personal это short

Далее в ходе скрита мы делаем так

Set PC_Personal to ( PC_Personal - 35 )

и это не работает - значение PC_Personal остается неизменным

однако вот это:

Set fuckBuff to PC_Personal
Set fuckBuff to ( fuckBuff - 35 )

работает как надо. В чем может быть бок?

Изменено пользователем Охотник за Смертью
Ссылка на комментарий
Поделиться на другие сайты

Может привлекательность была меньше 35? Ну, там 30 например, а short не ест отрицательные значения вроде? а на fuckbuff какой числовой тип висит? Или он вообще не прописан?
Ссылка на комментарий
Поделиться на другие сайты

Может привлекательность была меньше 35? Ну, там 30 например, а short не ест отрицательные значения вроде? а на fuckbuff какой числовой тип висит? Или он вообще не прописан?

тоже шорты там.

Отрицательность щас проверю, мне казалось, что она должна кушать отрицательность

 

апд

Шорты кушают отрицательные значения

Изменено пользователем Охотник за Смертью
Ссылка на комментарий
Поделиться на другие сайты

Попробуй сделать переменную, отслеживающую последовательность повышения переменных и заставляющую скрипт ее соблюдать.
Ссылка на комментарий
Поделиться на другие сайты

А не пробовал у PC_Personal убрать нижний слеш и оставить PCPerconal?

пробовал. Проблема вообще не понятно в чем, но с костылем работает отлично

 

Новый вопрос к вам, мои любители скриптописания. В МСФД есть такая фраза:

 

Более того, недавно я осознал, что подобный синтаксис работает и для глобальных скриптов:

 

set Global_script_name.variable to 1

 

Это полезно, чтобы избежать большого количества глобальных переменных или для отладки глобальных скриптов в консоли.

кто-то это тестил? а то у меня и не падает, но и не взлетает

 

И еще один вопрос :0-0:

Значения глобальных переменных сохраняются при сохранении/загрузке?

Ссылка на комментарий
Поделиться на другие сайты

Да, сохраняются.

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

Хм, странно. Впочем, я задал вопрос по этому поводу на нашем форуме. Но если и так, то 90% схшных квестов не будут работать при перезагрузке, ибо переменные, тем паче глобалы, там изобилуют.
Ссылка на комментарий
Поделиться на другие сайты

Скриптом его нормально не определишь, в диалогах есть функции.

Далее в ходе скрита мы делаем так

Set PC_Personal to ( PC_Personal - 35 )

и это не работает - значение PC_Personal остается неизменным

однако вот это:

Set fuckBuff to PC_Personal
Set fuckBuff to ( fuckBuff - 35 )

работает как надо. В чем может быть бок?

Ты из скриптов копировал? Просто поэкспериментируй с пробелами.

Новый вопрос к вам, мои любители скриптописания. В МСФД есть такая фраза:

 

кто-то это тестил? а то у меня и не падает, но и не взлетает

 

И еще один вопрос :0-0:

Значения глобальных переменных сохраняются при сохранении/загрузке?

1 скорее всего у тебя глобальный скрипт не запущен, добавь его в старт скрипт 2Как уже ответили - сохраняются, как и локальные. Только локальные действуют на 1 объект, а глобальные - как связующие нити между скриптами. Изменено пользователем Макс Кауфман
Ссылка на комментарий
Поделиться на другие сайты

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

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

Создать учетную запись

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

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

Войти

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

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

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