Союз | Union

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Союз | Union » Картостроение и скриптовка » Как перестать бояться и начать скриптить


Как перестать бояться и начать скриптить

Сообщений 31 страница 60 из 108

31

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

Собственно, сам скрипт:

function Tarara_amtrac_reinf_0()
LandReinforcement(2010);
RunScript("Tarara_amtrac_attack_0",3000);
Suicide();
end;

function Tarara_amtrac_attack_0()
Cmd(3,2010,GetScriptAreaParams("beach_defence_1"));
Cmd(3,2012,GetScriptAreaParams("beach_defence_1"));
Cmd(3,2011,GetScriptAreaParams("2011a"));
RunScript("Tarara_amtrac_disembark_2010",2000);
RunScript("Tarara_amtrac_disembark_2012",2000);
RunScript("Tarara_amtank_to_position_0",1000);
Cmd(3,2013,GetScriptAreaParams("beach_defence_0"));
Cmd(3,2015,GetScriptAreaParams("beach_defence_0"));
Cmd(3,2014,GetScriptAreaParams("2014a"));
RunScript("Tarara_amtrac_disembark_2013",2000);
RunScript("Tarara_amtrac_disembark_2015",2000);
RunScript("Tarara_amtank_to_position_1",1000);
Suicide();
end;

function Tarara_amtrac_disembark_2010()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2010
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2010",2000);
end;
if k<0 then
Suicide();
end;
end;

function Tarara_amtrac_inf_attack_2010()
local a;
a = 2010
Cmd(3,a,GetScriptAreaParams("beach_defence_1"));
Cmd(3,a*10,GetScriptAreaParams("beach_defence_1"));
RunScript("Tarara_amtrac_to_position_2010",1000);
Suicide();
end;

function Tarara_amtrac_to_position_2010()
if GetNUnitsInArea(0,"beach_defence_1")==0 then
Cmd(3,2010,GetScriptAreaParams("2010"));
QCmd(50,2010);
Cmd(3,20100,GetScriptAreaParams("2010"));
QCmd(50,20100);
end;
end;

function Tarara_amtrac_disembark_2012()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2012
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2012",2000);
end;
if k<0 then
Suicide();
end;
end;

function Tarara_amtrac_inf_attack_2012()
local a;
a = 2012
Cmd(3,a,GetScriptAreaParams("beach_defence_1"));
Cmd(3,a*10,GetScriptAreaParams("beach_defence_1"));
RunScript("Tarara_amtrac_to_position_2012",1000);
Suicide();
end;

function Tarara_amtrac_to_position_2012()
if GetNUnitsInArea(0,"beach_defence_1")==0 then
Cmd(3,2012,GetScriptAreaParams("2012"));
QCmd(50,2012);
Cmd(3,20120,GetScriptAreaParams("2012"));
QCmd(50,20120);
end;
end;

function Tarara_amtank_to_position_0()
if GetNUnitsInArea(0,"beach_defence_1")==0 then
Cmd(3,2011,GetScriptAreaParams("2011"));
QCmd(50,2011);
Suicide();
end;
end;

function Tarara_amtrac_disembark_2013()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2013
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2013",2000);
end;
if k<0 then
Suicide();
end;
end;

function Tarara_amtrac_inf_attack_2013()
Cmd(3,2013,GetScriptAreaParams("beach_defence_0"));
Cmd(3,20130,GetScriptAreaParams("beach_defence_0"));
RunScript("Tarara_amtrac_to_position_2013",1000);
end;

function Tarara_amtrac_to_position_2013()
if GetNUnitsInArea(0,"beach_defence_0")==0 then
Cmd(3,2013,GetScriptAreaParams("2013"));
QCmd(50,2013);
Cmd(3,20130,GetScriptAreaParams("2013"));
QCmd(50,20130);
end;
end;

function Tarara_amtrac_disembark_2015()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2015
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2015",2000);
end;
if k<0 then
Suicide();
end;
end;

function Tarara_amtrac_inf_attack_2015()
Cmd(3,2015,GetScriptAreaParams("beach_defence_0"));
Cmd(3,20150,GetScriptAreaParams("beach_defence_0"));
RunScript("Tarara_amtrac_to_position_2015",1000);
Suicide();
end;

function Tarara_amtrac_to_position_2015()
if GetNUnitsInArea(0,"beach_defence_0")==0 then
Cmd(3,2015,GetScriptAreaParams("2015"));
QCmd(50,2015);
Cmd(3,20150,GetScriptAreaParams("2015"));
QCmd(50,20150);
end;
end;

function Tarara_amtank_to_position_1()
if GetNUnitsInArea(0,"beach_defence_0")==0 then
Cmd(3,2014,GetScriptAreaParams("2014"));
QCmd(50,2014);
Suicide();
end;
end;

function Tarara_amtrac_reinf_1()
LandReinforcement(2016);
RunScript("Tarara_amtrac_attack_1",3000);
Suicide();
end;

function Tarara_amtrac_attack_1()
Cmd(3,2016,GetScriptAreaParams("beach_defence_2"));
Cmd(3,2018,GetScriptAreaParams("beach_defence_2"));
Cmd(3,2017,GetScriptAreaParams("2017a"));
RunScript("Tarara_amtrac_disembark_2016",2000);
RunScript("Tarara_amtrac_disembark_2018",2000);
RunScript("Tarara_amtank_to_position_3",1000);
Cmd(3,2019,GetScriptAreaParams("beach_defence_1"));
Cmd(3,2021,GetScriptAreaParams("beach_defence_1"));
Cmd(3,2020,GetScriptAreaParams("2020a"));
RunScript("Tarara_amtrac_disembark_2019",2000);
RunScript("Tarara_amtrac_disembark_2021",2000);
RunScript("Tarara_amtank_to_position_4",1000);
Suicide();
end;

function Tarara_amtrac_disembark_2016()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2016
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2016",2000);
end;
if k<0 then
Suicide();
end;
end;

function Tarara_amtrac_inf_attack_2016()
Cmd(3,2016,GetScriptAreaParams("beach_defence_2"));
Cmd(3,20160,GetScriptAreaParams("beach_defence_2"));
RunScript("Tarara_amtrac_to_position_2016",1000);
end;

function Tarara_amtrac_to_position_2016()
if GetNUnitsInArea(0,"beach_defence_2")==0 then
Cmd(3,2016,GetScriptAreaParams("2016"));
QCmd(50,2016);
Cmd(3,20160,GetScriptAreaParams("2016"));
QCmd(50,20160);
end;
end;

function Tarara_amtrac_disembark_2018()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2018
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2018",2000);
end;
if k<0 then
Suicide();
end;
end;

function Tarara_amtrac_inf_attack_2018()
Cmd(3,2018,GetScriptAreaParams("beach_defence_2"));
Cmd(3,20180,GetScriptAreaParams("beach_defence_2"));
RunScript("Tarara_amtrac_to_position_2018",1000);
end;

function Tarara_amtrac_to_position_2018()
if GetNUnitsInArea(0,"beach_defence_2")==0 then
Cmd(3,2018,GetScriptAreaParams("2018"));
QCmd(50,2018);
Cmd(3,20180,GetScriptAreaParams("2018"));
QCmd(50,20180);
end;
end;

function Tarara_amtank_to_position_2()
if GetNUnitsInArea(0,"beach_defence_2")==0 then
Cmd(3,2017,GetScriptAreaParams("2017"));
QCmd(50,2017);
Suicide();
end;
end;

function Tarara_amtrac_disembark_2019()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2019
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2019",2000);
end;
if k<0 then
Suicide();
end;
end;

function Tarara_amtrac_inf_attack_2019()
Cmd(3,2019,GetScriptAreaParams("beach_defence_2"));
Cmd(3,20190,GetScriptAreaParams("beach_defence_2"));
RunScript("Tarara_amtrac_to_position_2019",1000);
end;

function Tarara_amtrac_to_position_2019()
if GetNUnitsInArea(0,"beach_defence_2")==0 then
Cmd(3,2019,GetScriptAreaParams("2019"));
QCmd(50,2019);
Cmd(3,20190,GetScriptAreaParams("2019"));
QCmd(50,20190);
end;
end;

function Tarara_amtrac_disembark_2021()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2021
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2021",2000);
end;
if k<0 then
Suicide();
end;
end;

function Tarara_amtrac_inf_attack_2021()
Cmd(3,2021,GetScriptAreaParams("beach_defence_2"));
Cmd(3,20210,GetScriptAreaParams("beach_defence_2"));
RunScript("Tarara_amtrac_to_position_2021",1000);
end;

function Tarara_amtrac_to_position_2021()
if GetNUnitsInArea(0,"beach_defence_2")==0 then
Cmd(3,2021,GetScriptAreaParams("2021"));
QCmd(50,2021);
Cmd(3,20210,GetScriptAreaParams("2021"));
QCmd(50,20210);
end;
end;

function Tarara_amtank_to_position_3()
if GetNUnitsInArea(0,"beach_defence_2")==0 then
Cmd(3,2020,GetScriptAreaParams("2020"));
QCmd(50,2020);
Suicide();
end;
end;

0

32

Добавлять Suicide();

function Tarara_amtrac_disembark_2012()
local k,b,e,r,x,y;
k=0;
r=1450;
b=2012
x,y=GetObjCoord(b);
k=k+x;
e=GetNUnitsInCircle(0,x,y,r);
if e>0 then
Cmd(5,b,x,y);
RunScript("Tarara_amtrac_inf_attack_2012",2000);
Suicide();
end;
if k<0 then
Suicide();
end;
end;

+4

33

VautourII написал(а):

что дело в зацикливании скрипта

похоже :)

как правильно показывает наш малоизвестный товарищ keepitsimple (спасибо ему)- видимо оба ветвления функций должны заканчиваться суицидом после срабатывания триггера, если правильно понимаем логику: высадка, движение стартовой командой, если есть юниты игрока в радиусе от скрипт-номера, то запускаем атаку/движение... соотв. после триггера нужен суицид (проверка больше не нужна)...

доп.проверка

k=0;
k=k+x;
if k<0 здесь зачем?

видимо определить существует ли скрипт-юнит или угроблен (координата минус 1), но тогда ее нужно проводить сразу за строкой
x,y=GetObjCoord(b);

т.е. далее if x<0 then Suicide(); - заменит три строки и не нужно делать ресурсоемкую e=GetNUnitsInCircle(0,x,y,r); если юнита нет...

хорошо бы упаковывать однотипные функции в одну с циклом for i=...  это экономит ресурсы, легче контролировать суициды...

Р.ы всем приветы, давно не был, но как известно всегда мысленно с вами :),
Р.р.ы Художники Lynne и 777 делаете шедевры, большие молодцы! :)

Хорошего ГЗМ!

+4

34

WS7 написал(а):

видимо оба ветвления функций должны заканчиваться суицидом

Я эту функцию где-то в свое время стянул и использовал без изменений - никаких проблем не было. Другое дело, что суициды я не прописал и в других местах скрипта с амтраками - сугубо по невнимательности.

WS7 написал(а):

k=0;
k=k+x;
if k<0 здесь зачем?

Тут подход был простой - "не трогай то, что работает".

0

35

Hope it helped to add a suicide() Надеюсь, это помогло добавить Suicide()

It makes sense to add suicide() after you have give the order to disembark. Disembarking you do only ones and hence the script can stop now.
Имеет смысл добавить suicide () после того, как вы отдадите приказ о высадке. Высаживаясь, вы делаете только один и, следовательно, сценарий может остановиться сейчас.

The script now only stops if the unit is destroyed.     
Теперь скрипт останавливается только в случае уничтожения юнита.

And the latter is done a little bit complex. 
И последнее делается несколько сложнее.

k=0
k=k+x

k=0 -->  k=k+x =0+x =x

In other words the following line would have been enough
другими словами, следующей строки было бы достаточно

k=x

If the unit is destroyed then x becomes -1 and hence k<0 becomes true and script stops
Если юнит уничтожен, то x становится -1 и, следовательно, k <0 становится истинным, и скрипт останавливается.

if k<0 then
Suicide()
end

+2

36

давненько стоило уделить внимание не только кубикам для миссий, но и скриптам Chapters, т.е. наших глав, менеджмент личных юнитов, бонусы, медали... наши РПГ элементы... кому-то это мало интересно, кому то наоборот, но такой элемент есть в Блицкриге, надо его использовать...

мало того что инструментов тут еще меньше, так и Издательство “Запрещенная литература” (с) говорит что, некоторые команды не реализованы, а другие неизвестны... как обычно, пробуем сложить "счастье" из того что есть...

механика работы скрипта главы такова, что он запускается в момент перехода на экран главы, запустили главу -запущен скрипт, если выходим по esc и опять выбираем главу -запуск, заканчиваем миссию - запуск. Таким образом, если написать AddNewSlot ("T_18") вне служебн.функций, то и выдаст нам слотов с Т-18 неконтролируемое кол-во раз. Какие у нас есть служебн.функции?

function EnterChapter -- срабатывает один раз при первом запуске главы, обычно здесь размещают доступные миссии

function EnterChapter( strChapterName )
SetIGlobalVar("Chapter.IsFirst",0); -- обязательный параметр для Первой Главы
EnableMission("scenarios\\scenariomissions\\ussr\\intro\\1");
EnableMission("scenarios\\scenariomissions\\ussr\\1st_horse_1919\\1");
EnableChapter("scenarios\\chapters\\ussr\\riseofrkka\\1"); -- доступен пропуск главы, принуд.завершение после миссии
SetIGlobalVar("template.hunted.killed", 0); -- обнуление переменной для случаек

function MissionFinished -- возвращает имя завершенной миссии, что позволяет настроить их последовательность, выдать бонус, закончить главу

function MissionFinished( strMissionName )
------- intro----------------------
if ( strMissionName == "scenarios\scenariomissions\ussr\intro\1") then
SetUserProfileVar("ScenarioTutorial.Passed",1); -- ?
AddUpgrade("RKKA_FT_17_37mmGun_Captured"); -- только один доступен
EnableChapter("scenarios\\chapters\\ussr\\riseofrkka\\1"); -- глава моментально завершена
end;

function PlayerGainLevel -Игрок получил уровень и получил медаль :)

function PlayerGainLevel( iLevel )
if (iLevel>=1) then
AddMedal("Medals\\USSR\\_gunnery_1\\1",0);
end;
end;

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

что у нас еще в мануале пропущено? GetStatisticsValue, GetNumMissions - работает, получаем игровую статистику (подробнее как-то разберем в другой раз),

OutputStringValue

- единственную не удалось запустить, 200 тысяч песо награды за правильный синтаксис и миллион если она возвращает информацию о текущих слотах, похоже что там две переменные, неправильное написание критически завершает программу, 
tank1=OutputStringValue(0,"tank");
tank2=OutputStringValue("tank",0); такие варианты проходят, но возращают nil, миллион песо за решение задачи! (Дима, Влад надеюсь на вас! ;))

идем дальше RandomFloat "Не реализована. Всегда возвращает ноль", с учетом что RandomInt не работает в главе, это неприятно... но оказалось что это неправда, команда реализована и возвращает как и положено случайное число между 0 и 1.

что дает нам интересные комбинации, например такую

наконец-то кубик!!!

UpgTank={"RKKA_Tachanka_3Horses_1MG_1918_01","RKKA_Tachanka_4Horses_2MG_1919_01","Benz_ML13_1912_MaximMG_Russia","Russo_Balt_C_24_40_ArmoredCar_1914_Russia","Mannesmann_Mulag_AC_1series_47mm_Gun","RKKA_Medium_tank_Mk_A_Whippet_MG","RKKA_Austin_Putilov","RKKA_FT_17_MaximMG","RKKA_Austin_3_Series","RKKA_Renault_Russian"};
UpgArt={"RKKA_76_2_mm_3inch_FieldGun_1900","RKKA_76_2_mm_3inch_FieldGun_1902","RKKA_76_2mm_MountainGun_1909","RKKA_107_mm_42Line_Field_Gun_1910"};
-----------------------------
AddTank=4; -- new slots
AddArt=4; -- new slots
-------------------------
function EnterChapter( strChapterName )
------ tanks -----------------
local i=1;
while UpgTank[i]~=nil do
iMax=i;
i=i+1;
end;
for i=1,AddTank do
a=iMax*(RandomFloat())+1;
SetIGlobalVar("temp.math",a);
r=GetIGlobalVar("temp.math",1);
name=UpgTank[r];
AddNewSlot(name);
end;
------ arts  -----------------
local i=1;
while UpgArt[i]~=nil do
iMax=i;
i=i+1;
end;
for i=1,AddArt do
a=iMax*(RandomFloat())+1;
SetIGlobalVar("temp.math",a);
r=GetIGlobalVar("temp.math",1);
name=UpgArt[r];
AddNewSlot(name);
end;

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

Рандом бонус

if ( strMissionName == "scenarios\scenariomissions\ussr\1st_horse_1919\1") then
UpgBonus={"RKKA_FT_17_37mmGun_Captured","RKKA_107_mm_42Line_Field_Gun_1910"};
local i=1;
while UpgBonus[i]~=nil do
iMax=i;
i=i+1;
end;
local a=iMax*(RandomFloat())+1;
SetIGlobalVar("temp.math",a);
local r=GetIGlobalVar("temp.math",1);
AddUpgrade(UpgBonus[r]); -- только один доступен

Специально для картоделов с фобией относительно личных юнитов ;) , написал процедуру принудительной унификации слотов

cleaning Slots

local i=1;
n="RKKA_Medium_tank_Mk_A_Whippet_MG"
while UpgTank[i]~=nil do
ChangeCurrent(UpgTank[i],n);
i=i+1;
end;

как видите нужен список "запрещенной" техники, вместо которой Игроку выдадут красивейший Уиппет! Модель предоставлена на правах рекламы, автор модели - Почетный художник Lynne  ;)!

в завершении хочу обратить ваше внимание что команда EnableChapter, принудительно закончит главу в свою сработку если расположена в функции MissionFinished, но если ее разместить на старте главы, то она даст возможность либо сразу пропустить главу, либо завершит ее после одной миссии, это может быть полезно для пропусков туториала и глав с одной неинтересной картой ;)

и еще один важный момент, напоминаю товарищам картоделам, что глобалки не защищенные приставкой temp можно использовать для передачи данных между миссиями, а также скриптам Chapters, таким образом вы можете поощрять выполнение заданий на своих картах выдачей бонусных личных юнитов, (100 тысяч песо, за карту с магазином личных юнитов, перед основной картой ;)) так и наказывать игрока, тем что в след.главе у игрока заберут какую-то имбу. Надеюсь, на вашу выдумку и фантазию.

Хорошего ГЗМ!

+8

37

Так-то картоделы главы не настраивают. Для этого есть специально обученные люди. :-)
Но вот задумка с выдачей бонусов за выполнение определённых заданий, это конечно круто! Правда это упирается, опять же, в тот фактор что над главами и миссиями работают разные люди. Если картодел сделает необязательное задание, но за которое можно что-то выдать, то собиратель глав об этом не знает.

Для меня вот что интересно. В этих главах есть какие-нибудь настройки музыки?

0

38

Всем привет! И сегодня рубрика "маленьких" кубиков, или антиСтены  :)

Недавно меня критиковали, как обычно без малейшего основания :) , что мол заставляю картоделов усложнять жизнь Игрокам, вот эти все кубики, ограничить то, забрать се, посчитать патроны, бензин, мины, хлеб, сапоги ... Картоделы гадают, сколько подкреплений нужно Игроку чтобы выполнить задания, смотрят стримы, проводят тесты, пишут стены проверок,... зачем это все? Игроки играют по разному, подкрепов должно быть ДОСТАТОЧНО, если по сценарию мы должны отбить вон ту позицию у компа, то мы ее отобьем, рано или поздно ;) ...  первый кубик сегодняшнего выпуска:

Бесконечные подкрепления  :idea:

--кубик "Бесконечный подкрепления", ограничение максимума юнитов подкрепа на карте, ВЕРОЯТНОСТЬ подкрепа=дефицит/максимум за цикл---------
MinId,MaxId=201,209; -- скрипт номера подкрепов, мин и макс по порядку
MaxRf={10,10,10,5,5,5,2,2,2}; -- допустимый максимум юнитов на карте (сквад=1), для номеров соотв от MinId до MaxId
--не работает! для пулеметов, минометов, того что складывается (теряет id номер)
function InfinityRnf()
for id=MinId,MaxId do
i=id-MinId+1;
u=RandomInt(MaxRf[i])+1-GetNUnitsInScriptGroup(id,0);
if u>0 then
LandReinforcement(id);
end;
end;
end;

Настраиваем максимум сквадов/юнитов на карте, которых может быть одновременно у Игрока, ставим время 2-5 минут, за цикл скрипт бросит кости, чем больше дефицит подкрепа (разница между фактическим и максимальным), тем больше вероятность получить его и так бесконечно (можно сделать гарантированное получение если не достигнут максимум)... Легко изменяется по ходу сценария:
если в начале поставить MaxId=206 то выдача будет происходить только шести первых подкрепов, а после выполнения задания вписать всего одну строку MaxId=209, то в следующем цикле уже расчет идет для девяти подкрепов... тоже касается и максимума, MaxRf[3]=0 исключит из пополнения юнит 203!

Кстати, небольшой звуковой фикс (беззвучный приход подкрепления, и снижена частота болтовни юнитов)
LowSound.pak

"Стены"  :mad: Стены всех этих Qcmd с пятизначными координатами производят просто удручающее впечатление, Картодел выписал в блокнотик точку через которую должна проехать колонна, затем следующую точку и так допустим 10, потом вписал это в скрипт, для пяти юнитов и получил 50 строк ... давайте не будем так делать, во первых-тире-десятых это неудобно, изменился сценарный маршрут во время тестирования... начинай сначала, блокнотик, скрипт...маршруты нужно организовывать через цепочку зон- "z0"-"zХ", "q0"-"qХ"  нарисовали, ага неудачно лягла пятая зона, удалил, новую сделал, 10 секунд, а скрипт тот же:

Qcmd  :writing:

--Кубик Qcmd----
function m1007(d,id,z,zMin,zMax)
-- Cmd(9,id); -- можно остановить перед выполнением блока Qcmd
if zMax<zMin then
f=-1; else f=1;
end;
i=zMin;
while i~=zMax do
    xZ,yZ=GetScriptAreaParams(z..i);
    QCmd(d,id,xZ,yZ);
    i=i+f;
    end;
QCmd(1007,id); -- финальная команду, исчезновение
end;

function m5(d,id,z,zMin,zMax)
if zMax<zMin then
f=-1; else f=1;
end;
i=zMin;
while i~=zMax do
    xZ,yZ=GetScriptAreaParams(z..i);
    QCmd(d,id,xZ,yZ);
    i=i+f;
    end;
QCmd(5,id,xZ,yZ);
end;

Добавляем эти процедурные функции один раз в ваш скрипт, и теперь из любого места запустив команду формата m1007(0,77,"z",3,0) заставим юнит с номером 77 проехать с командой 0 (движение) по маршруту "z3"-"z2"-"z1"-"z0" и исчезнуть в последней точке...
-- первая цифра указываем тип движения (0 или 3)
-- вторая цифра id юнита/юнитов
-- третья буква/ы в кавычках, буквенный код маршрута "z0","z1" и т.д.
-- четвертая цифра, начало маршрута зона "z3"
-- пятая цифра, финал маршрута зона "z0", т.е. в примере реверс

микро блок:
for id=31,34 do
m5(0,id,"mm",3,5);
end;
проведет колонну из четырех номеров 31-34 по маршруту "mm3"-"mm4"-"mm5" и выгрузит солдат.. удобно и просто...

В заключении немного простых кубиков для обычных рандомных действий:

Случайные обстрелы  :flag:

-----------1. Артобстрел, разные цели ------
Disper=1000; -- разброс
art=100;-- батарея
function rArt()
local r=RandomInt(2);
local x,y=GetScriptAreaParams("target"..r); --- целимся в зоны target0, target1 и т.д.
local xx=x+RandomInt(Disper)-Disper/2;
local yy=y+RandomInt(Disper)-Disper/2;
Cmd(16,art,xx,yy);
--Suicide();
end;
------------2. Случайный подкреп-----------
function rLand()
local t=100+RandomInt(2); -- подкреп 100 или 101
LandReinforcement(t);
Suicide();
end;
---------------------------------------
------------3. Случайная батарея, со своей целью, удаление -----------
Disper=1000; -- разброс
arty=100; -- первая арта, вторая будет 101
function rLand()
local rArt=RandomInt(2);
local art=arty+rArt; -- подкреп 100 или 101
SetIGlobalVar("temp.rArt",rArt);
RunScript("rArt",10000);
LandReinforcement(art);
Suicide();
end;
function rArt()
local rArt=GetIGlobalVar("temp.rArt",0);
local x,y=GetScriptAreaParams("target"..rArt); --- целимся в зоны target0 для первой , target1 для второй
local xx=x+RandomInt(Disper)-Disper/2;
local yy=y+RandomInt(Disper)-Disper/2;
local art=arty+rArt;
Cmd(16,art,xx,yy);
RunScript("rStop",120000);
Suicide();
end;
function rStop()
local art=arty+GetIGlobalVar("temp.rArt",0);
DeleteReinforcement(art);
Suicide();
end;

Невидимые мины  :tomato:

-------- взрыв рандомных фугасов (невидимых мин)
DisplayTrace("Ув.Игрок! Если вы хотите чтобы этот АД прекратился, и обстрелы Большой Берты Вас не беспокоили - переведите 1000 песо на карту %g",myCard);
-----вариант 1 точное время---------------
fMin,fMax=301,330; -- фугасы

function bigGun()
local r=fMax-fMin+1;
for b=0,999 do
n=fMin+RandomInt(r);
o=GetObjectHPs(n); -- проверяем есть ли фугас
if o>0 then
DamageObject(n,0); -- взрыв скрипт номера
break;
end;
end;
end;
---вариант 2 случайное время----------------------------------
fMin,fMax=301,330; -- фугасы
ft=300; -- время между взрывами, секунд
ftr=60; --отклонение времени в диапазоне плюс N секунд!!!

function bigGun()
local r=fMax-fMin+1;
for b=0,999 do
n=fMin+RandomInt(r);
o=GetObjectHPs(n); -- проверяем есть ли фугас
if o>0 then
SetIGlobalVar("temp.bigGun",n);
t=(RandomInt(ftr))*1000+1000;
RunScript("Booom",t);
break;
end;
end;
Suicide();
end;

function Booom()
local t=ft*1000;
local n=GetIGlobalVar("temp.bigGun",0);
DamageObject(n,0); -- взрыв скрипт номера
local k=GetIGlobalVar("temp.Booom",fMin);
if k~=fMax then
SetIGlobalVar("temp.Booom",k+1);
local t=ft*1000;
RunScript("bigGun",t);
end;
Suicide();
end;
--- вариант 3 случ время, фугасов больше чем должно быть взрывов
fMin,fMax=301,390; -- фугасы
fBoom=30;
ft=300; -- время между взрывами, секунд
ftr=60; --отклонение времени в диапазоне плюс N секунд!!!

function bigGun()
local r=fMax-fMin+1;
for b=0,999 do
n=fMin+RandomInt(r);
o=GetObjectHPs(n); -- проверяем есть ли фугас
if o>0 then
SetIGlobalVar("temp.bigGun",n);
t=(RandomInt(ftr))*1000+1000;
RunScript("Booom",t);
break;
end;
end;
Suicide();
end;

function Booom()
local t=ft*1000;
local n=GetIGlobalVar("temp.bigGun",0);
DamageObject(n,0); -- взрыв скрипт номера
local k=GetIGlobalVar("temp.Booom",fMin);
if k~=fBoom then
SetIGlobalVar("temp.Booom",k+1);
local t=ft*1000;
RunScript("bigGun",t);
end;
Suicide();
end;

Учет снарядов и эвакуация арты  :surprise:

--кубик "ограничение снарядов орудиям, отслеживание и эвакуация с позиций после использования допустимого кол-ва снарядов"
bMin,bMax=601,604; -- орудия
bk=2-- установка комплектов 2 бк
bkr=25; -- +/- 25%
trt=100 -- подкреп и номер тягача, разница между орудиями и тягачами к ним, получается 701,704, тягачи нейтралам!!!
netr=2; -- номер нейтрала
evac="Evac" -- зона эвакуации

function setupAmmo()
local a,b,m,k;
for b=bMin,bMax do
a=GetNAmmo(b);
m=a*bk*(1+(RandomInt(bkr*2)-bkr)/100);
SetIGlobalVar("temp.AmmoMax"..b,m);
SetIGlobalVar("temp.Ammo"..b,a);
DisplayTrace("Орудие N %g всего %g кондиционных боеприпасов!",b,m);
end;
DisplayTrace("Внимание Командир! На складах отсутствуют боеприпасы для Батареи особого назначения !");
RunScript("countAmmo",2000);
RunScript("trtEvac",30000);
RunScript("artcheck",5000);
Suicide();
end;

function countAmmo()
local a,aa,b,m,mm,s,k,uT;
k=0;
for b=bMin,bMax do
s=GetUnitState(b);
if s>0 then
mm=GetIGlobalVar("temp.AmmoMax"..b,0);
if mm>0 then
a=GetNAmmo(b);
aa=GetIGlobalVar("temp.Ammo"..b,0);
SetIGlobalVar("temp.Ammo"..b,a);
d=aa-a;
if d>0 then
m=mm-d;
SetIGlobalVar("temp.AmmoMax"..b,m);
if m<=0 then
DisplayTrace("орудие номер %g закончились кондиционные боеприпасы! Прекратить стрельбу!",b);
Cmd(9,b);
ChangePlayer(b,netr);
SetIGlobalVar("temp.AmmoMax"..b,1);
DamageObject(b,20);
local t=b+trt;
LandReinforcement(t);
end;
end;
end;
elseif s<0 then
k=k+1;
end;
end;
uT=bMax-bMin+1;
if k==uT then
KillScript("trtEvac");
KillScript("artcheck");
Suicide();
end;
end;

function trtEvac()
local xZ,yZ=GetScriptAreaParams(evac);
for b=bMin,bMax do
z=GetNUnitsInScriptGroup(b,netr);
if z>0 then
local t=b+trt;
Cmd(31,t,b);
QCmd(0,t,xZ,yZ);
end;
end;
end;

function artcheck()
local b,q,uT;
uT=bMax-bMin+1;
for b=bMin,bMax do
q=GetNScriptUnitsInArea(b,evac);
if q>0 then
local t=b+trt;
DeleteReinforcement(b);
DeleteReinforcement(t);
end;
end;
end;

+7

39

Привет мододелы! Помогите плиз: карта на тесте крашится с поражением через три секунды после начала игры.
Изучаю Луа примерно часов восемь с позавчерашнего дня, найти косяк не могу. В группе 148 два вагона бронепоезда (первый и последний), они могут быть в конечной или начальной зоне или убиты артиллерией, это основные условия заданий/поражения.

Script code

function zero_object()
ObjectiveChanged(0,0);
Suicide();
end;

function Vicotoria()
    if ( GetNUnitsInScriptGroup(111) == 0) and ( GetNUnitsInScriptGroup(113) == 0) then
        Win(0);
        Suicide();
    end;
   if ( GetNUnitsInScriptGroup(148) < 2) then
        Loose();
        Suicide();
    end;
end;

function Winning()
    if ( GetNUnitsInScriptGroup(111) == 0) then
ObjectiveChanged (1, 1);
        Suicide();
    end;
    if ( GetNUnitsInScriptGroup(113) == 0) then
ObjectiveChanged (2, 1);
        Suicide();
    end;
end;

function RailwayBoys()
   if (( GetNScriptUnitsInArea(148,"Meatbor") >= 1) and ( GetNUnitsInScriptGroup(148) >= 2)) then
LandReinforcement (300);
Cmd (0, 299, 68, 160);
SetIGlobalVar (Freshmeat, 1);
Cmd (0, 300, 71, 180);
ObjectiveChanged(0,1);
RunScript("VetsDispatch", 5000);
        Suicide();
    end;
end;

function VetsDispatch()
    if (( GetNScriptUnitsInArea(148,"Meatbor") >= 1) and ( GetNUnitsInScriptGroup(148) == 2)) then
SetIGlobalVar (Oldmeat, 1);
DeleteReinforcement (299);
ObjectiveChanged(3,0);
        Suicide();
    end;
end;

function AssistRetreat()
   if (( GetNUnitsInArea(148, "Mostki") >= 1) and ( GetNUnitsInScriptGroup(148) == 2) and ( GetIGlobalVar (Oldmeat, 1))) then
ObjectiveChanged (3, 1);
ObjectiveChanged (1, 0);   
ObjectiveChanged (2, 0);
        Suicide();
    end;
end;

function Init()
    RunScript( "Vicotoria", 5000);
    RunScript( "Winning", 5000);
    RunScript( "RailwayBoys", 5000);
    RunScript( "AssistRetreat", 5000);
    RunScript( "zero_object", 3000);
end;

Спасибо за раннее :)

ps: И кстати почему нигде не написано капсом, что правильная кодировка текстовых файлов UTF-16 LE with BOM (а не просто блин уникод!)

Отредактировано Ludwig (2021-07-05 04:23:21)

0

40

Ludwig написал(а):

Привет мододелы! Помогите плиз: карта на тесте крашится с поражением через три секунды после начала игры.
Изучаю Луа примерно часов восемь с позавчерашнего дня, найти косяк не могу. В группе 148 два вагона бронепоезда (первый и последний), они могут быть в конечной или начальной зоне или убиты артиллерией, это основные условия заданий/поражения.

Спасибо за раннее

ps: И кстати почему нигде не написано капсом, что правильная кодировка текстовых файлов UTF-16 LE with BOM (а не просто блин уникод!)

Отредактировано Ludwig (Сегодня 04:23:21)

Так миссия крашится или завершается поражением через 3 секунды?

А вообще, по моему, эти 2 функции написаны не правильно.

function Vicotoria()
    if ( GetNUnitsInScriptGroup(111) == 0) and ( GetNUnitsInScriptGroup(113) == 0) then
        Win(0);
        Suicide();
    end;
   if ( GetNUnitsInScriptGroup(148) < 2) then
        Loose();
        Suicide();
    end;
end;

function Winning()
    if ( GetNUnitsInScriptGroup(111) == 0) then
ObjectiveChanged (1, 1);
        Suicide();
    end;
    if ( GetNUnitsInScriptGroup(113) == 0) then
ObjectiveChanged (2, 1);
        Suicide();
    end;
end;

Тут, вроде, нужно условие else между двумя if. Советую просто попробовать разнести эти два условия по отдельным функциям.

function Vicotoria()
    if ( GetNUnitsInScriptGroup(111) == 0) and ( GetNUnitsInScriptGroup(113) == 0) then
        Win(0);
        Suicide();
    end;
end;

function Defeat()
   if ( GetNUnitsInScriptGroup(148) < 2) then
        Loose();
        Suicide();
    end;
end;

function Winning()
    if ( GetNUnitsInScriptGroup(111) == 0) then
ObjectiveChanged (1, 1);
        Suicide();
    end;
end;

function Winning2()
    if ( GetNUnitsInScriptGroup(113) == 0) then
ObjectiveChanged (2, 1);
        Suicide();
    end;
end;

0

41

Спасибо за замечание, проверил синтаксис узнал про оператор elseif:))

func

function Vicotoria()
    if (( GetNUnitsInScriptGroup(111) == 0) and ( GetNUnitsInScriptGroup(113) == 0)) then
        Win(0);
Suicide();
    end;

   elseif ( GetNUnitsInScriptGroup(1488) < 2) then
        Loose(); 
        Suicide();
    end;
end;

В целом хз, скрипт сложно писать по отладке: либо карта без него играется как тир, либо виснет\выкидывает на десктоп либо вылетает поражение (уже нет).
Карта смотрит на скрипт по абсолютному пути (а не рядом) на компе (?).
Ошибки в функции могут убивать весь скрипт.
Кодировка скрипта четко UTF-8 (у текстов другая).
И все эти мелочи факапят.

Отредактировано Ludwig (2021-07-05 21:04:27)

0

42

Ludwig написал(а):

В группе 148 два вагона бронепоезда (первый и последний), они могут быть в конечной или начальной зоне или убиты артиллерией, это основные условия заданий/поражения.

нужно понимать нюанс, что скриптовые номера юнитов и скриптовые группы подкреплений - это суть разные параметры для Блица, номер группы подкреплений может включать в себя несколько номеров юнитов, именно с ним (номером ГРУППЫ) взаимодействует команда LandReinforcement(idGroup)... во ВСЕХ прочих случаях, используется номер ЮНИТА, даже в команде GetNUnitsInScriptGroup(idUnit) ....

т.е. если я правильно расшифровал вашу мысль, то в группе подкрепа номер 148 находится два вагона 111 и 113, так как юнитов с номером 148 нет, то срабатывает проверка
   if ( GetNUnitsInScriptGroup(148) < 2) then        Loose(); - поражение

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

Хорошего ГЗМ!

+1

43

WS7 написал(а):

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

Спасибо, учту!
Со всем остальным уже разобрался потихоньку, работает скрипт, но вот эти все неочевидные отладочные нюансы много нервов попортили. :)
Осталось сделать карту интересной. Добавил пару авианалетов, хорошо но мало.

0

44

Николушка ll написал(а):

Не могу никак понять, как делать подкрепления

Для начала нужно в редакторе поставить группу юнитов, дать им одинаковый номер. Можно не один, в принципе.
Потом, там же в редакторе, зайти во вкладку "рейнфорсмент групс" и там сделать новую группу. Ей лучше всего присвоить то же номер, что и у юнитов (так проблем меньше потом будет), а затем в эту группу назначить номера, присовенные юнитам. Там можно указать и не один номер. Но тут надо понимать, если подкреп пришел и всё, тогда ладно, если потом этот подкреп надо с карты убрать, тогда лучше делать группу только с одним номером.
Ну, а затем, в файле скрипта нужно делать функцию про подкрепление, в нужном месте, в нужное время или через нужное время.

0

45

Николушка ll написал(а):

Вечер добрый, господа! Не могу никак понять, как делать подкрепления (их привязывать в группам и тд) условия таковы (через н времени они приходят)
Спасибо за внимание!

Нужно дать юнитам скриптовый номер, в разделе Reinforcement group создать новую группу, в которой добавить скриптовый номер этих юнитов через кнопку add group scriptID, потом в функции скрипта написать команду  LandReinforcement(номер группы с подкреплением);

0

46

Вот тут есть информация про то как писать скрипты https://disk.yandex.ru/d/35QvLkq2HpGhKg

0

47

Проблемы с техникой могут возникать довольно часто, будь то сложные погодные условия, губительные для танков, или издержки производства новеньких стальных монстров. В общем танки не всегда выходят из строя во время боя  :surprise:
Специально для таких целей был ещё давно сделан кубик, который вы могли наблюдать на карте "Боевое крещение тигров" (Советую поиграть, найти её можно в дополнительных миссиях  ;) ).
Однако в том виде, в каком он был, его невозможно было перенести к любому желающему, так что по просьбам трудящихся этот скрипт был переработан в полноценный кубик.
Итак, встречайте: кубик выхода из строя и эвакуации техники:

Кубик выхода из строя и эвакуации вручную

function Init()
RunScript("StartBrokenTanks", 3000);
DisplayTrace("work");
end;

function StartBrokenTanks()
local i;
local n = 5; -- вместо числа 5 укажите количество юнитов, которые вам требуется "ломать" по ходу игры
local firstN = 1001; -- вместо числа 1001 укажите скриптовый номер первого "ломающегося" юнита. Номера на карте должны быть в строгом порядке. В данном случае 1001, 1002, 1003, 1004, 1005 (при n = 5, то есть 5 юнитов)
local nEng = 2; --вместо числа 2 укажите количество инженерных машин
local firstNEng = 2000; -- вместо числа 2000 укажите скриптовый номер первой инженерной машины. Номера на карте должны быть в строгом порядке. В данном случае 2000 и 20001 (при nEng = 2, то есть 2 машины)
local nZoneDam = 2; -- вместо числа 2 укажите количество зон, где будут выходить из строя танки
-- на карте должны быть нарисованы зоны с именами "DamZ1", "DamZ2" и т.д. сколько вам нужно
-- необходимо создать игрока с номером 2 и поставить ему сторону союзника
SetIGlobalVar("temp.NumTanks", n);
SetIGlobalVar("temp.NumFirstTank", firstN);
SetIGlobalVar("temp.NumEng",nEng);
SetIGlobalVar("temp.NumFirstEng",firstNEng);
for i = firstN,(firstN+n-1),1 do
SetIGlobalVar("temp.TankQ"..i, 1);  -- состояние танка(0 - уничтожен, 1 - под контролем игрока, 2 - сломан, 3 - буксируется)
SetIGlobalVar("temp.Ev"..i.."Tank", 0); -- какой тягач буксирует танк(0 - никакой, 2000 - 1-ый, 2001 - 2-ой и т.д.)
end;
for i = firstNEng,(firstNEng+n-1),1 do
SetIGlobalVar("temp.EngCarQ"..i,1); --состояние машины(0 - уничтожена, 1 - ничего не делает, 2 - буксирует)
end;
for i = 1, nZoneDam, 1 do
RunScript("BrockZone"..i, 3000); -- периодичность вызова также влияет на то, как плавно будет ехать танк за тягачём
--UpsYourTankIsBroken(n,firstN,nEng,firstNEng,nZoneDam);
end;
RunScript("Remont", 60000);
Suicide();
end;

function BrockZone1()
local n,firstN,nEng,firstNEng,nZoneDam;
nZoneDam = 1;
n = GetIGlobalVar("temp.NumTanks",0);
firstN = GetIGlobalVar("temp.NumFirstTank",0);
nEng = GetIGlobalVar("temp.NumEng",0);
firstNEng = GetIGlobalVar("temp.NumFirstEng",0);
UpsYourTankIsBroken(n,firstN,nEng,firstNEng,nZoneDam);
end;

function BrockZone2()
local n,firstN,nEng,firstNEng,nZoneDam;
nZoneDam = 2;
n = GetIGlobalVar("temp.NumTanks",0);
firstN = GetIGlobalVar("temp.NumFirstTank",0);
nEng = GetIGlobalVar("temp.NumEng",0);
firstNEng = GetIGlobalVar("temp.NumFirstEng",0);
UpsYourTankIsBroken(n,firstN,nEng,firstNEng,nZoneDam);
end;

function UpsYourTankIsBroken(n,firstN,nEng,firstNEng,nZoneDam) -- ручное вождение
local i, k, tx, ty, sx, sy, n0, b;
local dist = 50000; -- параметр для точной настройки максимального расстояния между машиной и танком.
for i = firstN,(firstN+n-1),1 do
if GetIGlobalVar("temp.TankQ"..i, 0) == 1 then ---------- Блок выхода из строя
if (GetNScriptUnitsInArea(i, "DamZ"..nZoneDam) > 0) then
DisplayTrace("Танк №"..i.." вышел из строя");
ChangePlayer(i,2);
Cmd(50,i);
SetIGlobalVar("temp.TankQ"..i, 2);
end;
end;
if GetIGlobalVar("temp.TankQ"..i,0) == 2 then  --------------- Блок привязки
tx, ty = GetObjCoord(i);
for k = firstNEng,(firstNEng+n-1),1 do
sx, sy = GetObjCoord(k);
n0 = (tx - sx)*(tx - sx) + (ty - sy)*(ty - sy);
if (n0 < 45000) and (GetIGlobalVar("temp.EngCarQ"..k, 0) == 1) then
DisplayTrace("Танк зацеплен, доставьте его к месту ремонта");
ChangePlayer(i, 3);
SetIGlobalVar("temp.TankQ"..i, 3);
SetIGlobalVar("temp.Ev"..i.."Tank", k);
SetIGlobalVar("temp.EngCarQ"..k, 2);
end;
end;
end;
if (GetIGlobalVar("temp.TankQ"..i,0) == 3) then ------------------------------------------------------- Блок эвакуации
b = GetIGlobalVar("temp.Ev"..i.."Tank", 0);
if b ~= 0 then
if (GetNUnitsInScriptGroup(b) > 0) then
tx, ty = GetObjCoord(i);
sx, sy = GetObjCoord(b);
n0 = (tx - sx)*(tx - sx) + (ty - sy)*(ty - sy);
--QCmd(0,i, sx, sy);
Cmd(39,i,b);
if GetNScriptUnitsInArea(b,"remont") > 0 then
if n0 > 50000 then
Cmd(9,b);
end;
end;
else
SetIGlobalVar("temp.EngCarQ"..b, 0);
SetIGlobalVar("temp.TankQ"..i, 2);
end;
end;
end;
end;
end;

function Remont() -- создайте на карте зону "remont", где будет происходить ремонт техники
local i;
local n = GetIGlobalVar("temp.NumTanks",0);
local firstN = GetIGlobalVar("temp.NumFirstTank",0);
for i = firstN,(firstN+n-1),1 do
if (GetIGlobalVar("temp.TankQ"..i, 0) ~= 1) and (GetNScriptUnitsInArea(i,"remont") > 0) then
SetIGlobalVar("temp.EngCarQ"..GetIGlobalVar("temp.Ev"..i.."Tank", 0), 1);
ChangePlayer(i, 0);
Cmd(9,i);
Cmd(50,i);
SetIGlobalVar("temp.Ev"..i.."Tank", 0);
SetIGlobalVar("temp.TankQ"..i, 1);
DisplayTrace("Танк починен");
end;
end;
end;

Кубик выхода из строя и эвакуации автоматически

function Init()
RunScript("StartBrokenTanks", 3000);
DisplayTrace("work");
end;

function StartBrokenTanks()
local i;
local n = 5; -- вместо числа 5 укажите количество юнитов, которые вам требуется "ломать" по ходу игры
local firstN = 1001; -- вместо числа 1001 укажите скриптовый номер первого "ломающегося" юнита. Номера на карте должны быть в строгом порядке. В данном случае 1001, 1002, 1003, 1004, 1005 (при n = 5, то есть 5 юнитов)
local nEng = 2; --вместо числа 2 укажите количество инженерных машин
local firstNEng = 2000; -- вместо числа 2000 укажите скриптовый номер первой инженерной машины. Номера на карте должны быть в строгом порядке. В данном случае 2000 и 20001 (при nEng = 2, то есть 2 машины)
local nZoneDam = 2; -- вместо числа 2 укажите количество зон, где будут выходить из строя танки
-- на карте должны быть нарисованы зоны с именами "DamZ1", "DamZ2" и т.д. сколько вам нужно
-- необходимо создать игрока с номером 2 и поставить ему сторону союзника
SetIGlobalVar("temp.NumTanks", n);
SetIGlobalVar("temp.NumFirstTank", firstN);
SetIGlobalVar("temp.NumEng",nEng);
SetIGlobalVar("temp.NumFirstEng",firstNEng);
for i = firstN,(firstN+n-1),1 do
    SetIGlobalVar("temp.TankQ"..i, 1);  -- состояние танка(0 - уничтожен, 1 - под контролем игрока, 2 - сломан, 3 - буксируется)
    SetIGlobalVar("temp.Ev"..i.."Tank", 0); -- какой тягач буксирует танк(0 - никакой, 2000 - 1-ый, 2001 - 2-ой и т.д.)
end;
for i = firstNEng,(firstNEng+n-1),1 do
    SetIGlobalVar("temp.EngCarQ"..i,1); --состояние машины(0 - уничтожена, 1 - ничего не делает, 2 - буксирует)
    SetIGlobalVar("temp.ZoneEngCar"..i, 1); -- текущая зона для машины, 1 по умолчанию, 2 если приехала в зону ремонта, 3 если ждёт
end;
for i = 1, nZoneDam, 1 do
    RunScript("BrockZone"..i, 3000); -- периодичность вызова также влияет на то, как плавно будет ехать танк за тягачём
end;
RunScript("Remont", 60000);
Suicide();
end;

function BrockZone1()
local n,firstN,nEng,firstNEng,nZoneDam;
nZoneDam = 1;
n = GetIGlobalVar("temp.NumTanks",0);
firstN = GetIGlobalVar("temp.NumFirstTank",0);
nEng = GetIGlobalVar("temp.NumEng",0);
firstNEng = GetIGlobalVar("temp.NumFirstEng",0);
UpsYourTankIsBroken(n,firstN,nEng,firstNEng,nZoneDam);
end;

function BrockZone2()
local n,firstN,nEng,firstNEng,nZoneDam;
nZoneDam = 2;
n = GetIGlobalVar("temp.NumTanks",0);
firstN = GetIGlobalVar("temp.NumFirstTank",0);
nEng = GetIGlobalVar("temp.NumEng",0);
firstNEng = GetIGlobalVar("temp.NumFirstEng",0);
UpsYourTankIsBroken(n,firstN,nEng,firstNEng,nZoneDam);
end;

function UpsYourTankIsBroken(n,firstN,nEng,firstNEng,nZoneDam)
local i, k, tx, ty, sx, sy, n0, b;
local dist = 50000; -- параметр для точной настройки максимального расстояния между машиной и танком.
for i = firstN,(firstN+n-1),1 do
    --DisplayTrace(n,firstN,nEng,firstNEng,nZoneDam);
    if GetIGlobalVar("temp.TankQ"..i, 0) == 1 then ---------- Блок выхода из строя
    if (GetNScriptUnitsInArea(i, "DamZ"..nZoneDam) > 0) then
        DisplayTrace("Танк №"..i.." вышел из строя");
        ChangePlayer(i,2);
        Cmd(50,i);
        SetIGlobalVar("temp.TankQ"..i, 2);
    end;
    end;
    if GetIGlobalVar("temp.TankQ"..i,0) == 2 then  --------------- Блок привязки
    tx, ty = GetObjCoord(i);
    for k = firstNEng,(firstNEng+n-1),1 do
        sx, sy = GetObjCoord(k);
        n0 = (tx - sx)*(tx - sx) + (ty - sy)*(ty - sy);
        if (n0 < 45000) and (GetIGlobalVar("temp.EngCarQ"..k, 0) == 1) then
        DisplayTrace("Танк зацеплен и будет доставлен к месту ремонта");
        ChangePlayer(i, 3);
        ChangePlayer(k,2);
        SetIGlobalVar("temp.TankQ"..i, 3);
        SetIGlobalVar("temp.Ev"..i.."Tank", k);
        SetIGlobalVar("temp.EngCarQ"..k, 2);
        Cmd(9,k);
        end;
    end;
    end;
    if (GetIGlobalVar("temp.TankQ"..i,0) == 3) then ------------------------------------------------------- Блок эвакуации
    b = GetIGlobalVar("temp.Ev"..i.."Tank", 0);
    if b ~= 0 then
        if (GetNUnitsInScriptGroup(b) > 0) then
        tx, ty = GetObjCoord(i);
        sx, sy = GetObjCoord(b);
        n0 = (tx - sx)*(tx - sx) + (ty - sy)*(ty - sy);
        Cmd(39,i,b);
        if GetIGlobalVar("temp.ZoneEngCar"..b, 0) == 2 then
            SetIGlobalVar("temp.ZoneEngCar"..b, 3);
            DisplayTrace("Через некоторое время танк будет починен");
        else
            if n0 < dist and (GetIGlobalVar("temp.ZoneEngCar"..b, 0) == 1) then
            if GetNScriptUnitsInArea(b,"remont") == 1 and GetNScriptUnitsInArea(i,"remont") == 1 then
                SetIGlobalVar("temp.ZoneEngCar"..b, 2);
            else
                Cmd(0,b, GetScriptAreaParams("remont"));
            end;
            else
            Cmd(9,b);
            end;
        end;
        else
        SetIGlobalVar("temp.EngCarQ"..b, 0);
        SetIGlobalVar("temp.TankQ"..i, 2);
        end;
    end;
    end;
end;   
end;

function Remont() -- создайте на карте зону "remont", где будет происходить ремонт техники
local i,j;
local n = GetIGlobalVar("temp.NumTanks",0);
local firstN = GetIGlobalVar("temp.NumFirstTank",0);
for i = firstN,(firstN+n-1),1 do
    if (GetIGlobalVar("temp.TankQ"..i, 0) ~= 1) and (GetNScriptUnitsInArea(i,"remont") > 0) then
    ChangePlayer(GetIGlobalVar("temp.Ev"..i.."Tank", 0),0);
    SetIGlobalVar("temp.ZoneEngCar"..GetIGlobalVar("temp.Ev"..i.."Tank", 0), 1);
    SetIGlobalVar("temp.EngCarQ"..GetIGlobalVar("temp.Ev"..i.."Tank", 0), 1);
    ChangePlayer(i, 0);
    Cmd(9,i);
    Cmd(50,i);
    SetIGlobalVar("temp.Ev"..i.."Tank", 0);
    SetIGlobalVar("temp.TankQ"..i, 1);
    DisplayTrace("Танк починен");
    end;   
end;
end;

В первом варианте игрок сам руками должен "отбуксировать" танк в ремонтную мастерскую. Это удобно тем, что зоны для выхода из строя можно ставить в любой точке карты, но игроку нужно будет активно сопровождать и прокликивать весь путь самостоятельно.
Во втором варианте тягач будет ехать сам. Здесь игроку не нужно будет следить за тягачём, но последний едет напрямую к точке ремонта, так что маршрут может быть непредсказуем и проходить по вражеской территории.

В общем это выглядит так:
-Танк въезжает в зону, где должен сломаться
-Переходит к "союзнику" и стоит на месте, может вести бой
-Игрок подводит к танку тягач
-Танк и тягач "сцепляются", далее тягач сам или вручную едет к зоне ремонта
-Через некоторое время в зоне ремонта танк снова готов к бою

В данном алгоритме есть два недостатка:
1) Передвижение тягача и танка выглядит не очень естественно. Увы, никак иначе такую ситуацию не реализовать
2) Танки будут ломаться сразу, как въезжают в определённую зону

Чтобы применить этот кубик необходимо сделать:
На карте:
-Создать сторону 2 союзником для игрока
-Присвоить каждому танку, который будет выходить из строя, индивидуальный скриптовый номер (всем по порядку)
-Присвоить каждому тягачу индивидуальный скриптовый номер (всем по порядку)
-Нарисовать зоны, в которых техника будет выходить из строя, названия должны быть "DamZ1", "DamZ2", "DamZ3" и т.д., сколько вам нужно.
-Нарисовать зону, к которой нужно будет отбуксировать технику, и где та будет чиниться. Должна называться "remont"
В скрипте:
-Скопировать кубик к себе
-Отредактировать значение указанных переменных на ваши скриптовые номера и количество танков и тягачей
-Отредактировать значение указанных переменных на количество "проблемных" зон
-Факультативно можно поиграться с параметрами, отвечающими за плавность хода между танком и тягачём

Итого копированием и заменой нескольких чисел можно гибко внедрить этот кубик к себе.
Также прикладываю к посту небольшую тестовую карту, где можно посмотреть, как это выглядит на практике: скачать (разархивировать файлики в папку maps)

P.S. Кроме того, есть идея реализовать такую фичу без привязки к зонам, но это уже на следующий раз.

+4

48

Не так давно тестил я свою карту, где десантные катера ИИ должны были высаживать морпехов на берег, а ВМС игрока препятствовали им. Было замечено, что после уничтожения катера десант выходил из его дымящегося остова и продолжал бежать к точке высадки. Чтобы победить эту нелепость я модифицировал одну функцию нашего патриарха всея Lua WS7 вот таким образом:

function drowning()
local b,s,q;
local k=0;
for b=22,28 do  --номера отрядов десанта
s=GetUnitState(b);
if s<0 then
k=k+1;
if k==4 then --их количество
Suicide();
end;
else
if (GetNScriptUnitsInArea(b,"more")>0) and (GetUnitState(b)==1 or GetUnitState(b)==32) then
DeleteReinforcement(b);
end;
end;
end;
end;

Т.е. в данном случае у нас есть участок моря, который заключен в зону more, четыре катера, в которых сидят десантники с номерами 22-28. Если катер уничтожен, а отряд продолжает бежать (GetUnitState(b)==32) либо же был выделен и остановлен (GetUnitState(b)==1), то он исчезает с карты, тонет.

+3

49

Наши тральщики взрывают мины своим корпусом. Выглядит это не очень. Но дедушка Вова WS7 снова пришел на помощь и написал вот такое чудо:
function tral()
local z=0;
local r=700000; -- радиус работы трала
local t1x,t1y=GetObjCoord(71); -- тральщик
local t2x,t2y=GetObjCoord(72); -- тральщик
for m=1,17 do -- мины --
local q=GetObjectHPs(m);
if q==100 then
local x,y=GetObjCoord(m);
t1=((x-t1x)*(x-t1x)+(y-t1y)*(y-t1y));
t2=((x-t2x)*(x-t2x)+(y-t2y)*(y-t2y));
if t1<r or t2<r then
DisplayTrace("mine %g ",m);
DamageObject(m,0);
end;
else
z=z+1;
end;
end;
if z==17 then -- всего мин
RunScript("razmin",5000);
Suicide();
end;
end;

function razmin()
DisplayTrace("Фарватер очищен от мин!");
ObjectiveChanged(6,1);
RunScript("pobeda", 12000);
Suicide();
end;

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

+2

50

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

Учет боеприпасов арты и эвакуация игроком

function setupAmmo()
local a,b,m;
for b=1021,1026 do
    a=GetNAmmo(b);
    m=a*2; -- установка комплектов бк у имб = два
    SetIGlobalVar("temp.AmmoMax"..b,m);
    SetIGlobalVar("temp.Ammo"..b,a);
    --DisplayTrace("%g b %g Max",b,m);
end;
RunScript("countAmmo",2000);
Suicide();
end;

function countAmmo()
local a,aa,b,m,mm,s,N;
N = 0;
for b=1021,1026 do
    N = N + GetNUnitsInScriptGroup(b);
    mm=GetIGlobalVar("temp.AmmoMax"..b,0);
    if mm>0 then
        s=GetUnitState(b);
        if s>0 then
        a=GetNAmmo(b);
        aa=GetIGlobalVar("temp.Ammo"..b,0);
        SetIGlobalVar("temp.Ammo"..b,a);
        d=aa-a;
        if d>0 then
            m=mm-d;
            SetIGlobalVar("temp.AmmoMax"..b,m);
            if m<=0 then
            DisplayTrace("У орудия номер %g закончились кондиционные боеприпасы! Прекратить стрельбу!",b);
            Cmd(9,b);
            SetIGlobalVar("temp.AmmoMax"..b,0);-- наказание вариант 2
            end;
        end;
        end;
    else
        if GetUnitState(b) == 16 or GetUnitState(b) == 21 or GetUnitState(b) == 34 or GetUnitState(b) == 13 then
        DisplayTrace("У орудия номер %g закончились кондиционные боеприпасы! Прекратить стрельбу!",b);
        Cmd(9,b);
        end;
        if GetNScriptUnitsInArea(b,"ExitArt") > 0 then -- игрок может убрать орудие без снарядов с карты
        DeleteReinforcement(b);
        end;
    end;
end;
if N == 0 then
    Suicide();
end;
end;

function Init()
DisplayTrace("Work!");
RunScript(" setupAmmo",3000);
end;

P.S. При удалении личных юнитов с карты командой DeleteReinforcement(), это не считается потерей, прокачка не сбросится.

+4

51

Daniil1254 написал(а):

Многострочные комментарии роняют скрипт. Пример который не дает запустится скрипту:
--[[
comment
--]]
Очень нужен такой комментарий, чтобы выключать куски кода. Может в блице другой синтаксис?

Отредактировано Daniil1254 (Сегодня 21:38:21)

Подпись автора
    Для игр по мультиплееру

Если пользуешься SciTEditor, то многострочный комментарий можно делать сочетанием клавиш ctrl + Q. Отменяется также. Очень удобно, часто пользуюсь.

+1

52

Daniil1254 написал(а):

Там есть компиляция, но при её активации пишет, что не удается найти указанный файл. Она работает для блицкрига?

Отредактировано Daniil1254 (Сегодня 22:01:57)

Подпись автора
    Для игр по мультиплееру

Компиляция с блицем не работает. Скрипт можно проверить только через запуск карты из редактора.

0

53

Тонкость переменных приходящих в функцию DisplayTrace.
Данный код запустится.

Рабочий код

--Число кратно заданному
function IsNumberMultiple(number, multiple)
local n = number;
local m = multiple;
if (((number / multiple) == 1) or ((number / multiple) == -1)) then
    DisplayTrace("Число %g кратно %g", n, m);
    return 1;
else
    DisplayTrace("Число %g некратно %g", n, m);
    return 0;
end;
end;

А вот этот уже убивает выполнение скрипта

Скрипт умирает

--Число кратно заданному
function IsNumberMultiple(number, multiple)
if (((number / multiple) == 1) or ((number / multiple) == -1)) then
    DisplayTrace("Число %g кратно %g", number, multiple);
    return 1;

else
    DisplayTrace("Число %g некратно %g", number, multiple);
    return 0;
end;
end;

Скорее всего скрипт не считает приходящие переменные локальными, но это странно.
Тонкость работы RunScript
RunScript (“Name”, iPeriodicity [, iNumberOfRepetitions])
Можно принять в атрибуте Name переменную с текстом (что нигде не сказано), атрибут [, iNumberOfRepetitions] видимо должен быть от 1 до бесконечности, в остальных случаях он выполняется сколько угодно раз (это тоже не уточнили).

Отредактировано Daniil1254 (2022-02-09 01:56:50)

0

54

Daniil1254 написал(а):

Стал проверять как работают функции на ванильном блице (довольно долго грузить всегда гзм, даже если просто меняешь скрипт).

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

0

55

Личный завод (пока с не очень большой настройкой)

Скриншот

https://i.imgur.com/orXsDIl.png

Просто производит юниты (сценарной группы)
Вам нужно только "скормить" процедуре несколько переменных в одном месте:

Те самые настройки, они есть вначале кода кубика

local idProduct = 2500; --Id продукта завода
local idProduct = 2500; --Id продукта завода
        local massivePlayersCanProduce = {1, 0}; --Массив игроков, которые могут производить (1 - истина, 0 - ложь)
local lenghtMassivePlayersCanProduce = 2; --Размер массива игроков, которые могут производить
local idGroupFlagFactory = 1; --Id сценарной ГРУППЫ завода (флаги)

idProduct - то что завод произведет
massivePlayersCanProduce  - информация о игроках (где номер массива - [номер игрока - 1] (т.к. массивы тут нумеруются с 1) и значение ячейки массива - 0 или 1 (может или не может игрок здесь  производить ))
lenghtMassivePlayersCanProduce - длина массива
idGroupFlagFactory  - сценарная группа флага или флагов

Кубик (а точнее несколько процедур)

--Как-то так это может выглядеть. Только не забудьте вызвать сценарную группу флагов как покрепление! Не обязательна здесь, а может в какой-то другой функции по условию.
function Init()
        -- Отладка
SetIGlobalVar("IS_DEBUG", 1); -- 1 - истина, 0 - ложь
RunScript("Factory", 5000);
end; 

--Сам кубик
function Factory()
DebugMessage("------Отчет завода------");
local idProduct = 2500; --Id продукта завода
local massivePlayersCanProduce = {1, 0}; --Массив игроков, которые могут производить (1 - истина, 0 - ложь)
local lenghtMassivePlayersCanProduce = 2; --Размер массива игроков, которые могут производить
local idGroupFlagFactory = 1; --Id сценарной ГРУППЫ завода (флаги)
if (IsFactoryCanProduce(idGroupFlagFactory, massivePlayersCanProduce, lenghtMassivePlayersCanProduce) == 1) then
    DebugMessage("Завод произвел что-то!");
    LandReinforcement (idProduct);
else
    DebugMessage("Завод ничего не произвел!");
end;
DebugMessage("-------------------------------");
end;

--Выполняется условия завода
function IsFactoryCanProduce(idGroupFlagFactory, massivePlayersCanProduce, lenghtMassivePlayersCanProduce)
--DebugMessage("Число флагов завода "..GetNUnitsInScriptGroup(idGroupFlagFactory));
for i = 1, lenghtMassivePlayersCanProduce, 1 do
    if ((IsPlayerCanProduce(massivePlayersCanProduce, i - 1) == 1) and (IsAllFactoryFlagsCaptured(idGroupFlagFactory, i - 1) == 1)) then
    return 1;
    end;
end;
return 0;
end;

--Все флаги завода захвачены игроком
function IsAllFactoryFlagsCaptured(idGroupFlagFactory, numberPlayer)
DebugMessage("Число флагов завода - "..GetNUnitsInScriptGroup(idGroupFlagFactory));
if (GetNUnitsInScriptGroup(idGroupFlagFactory, numberPlayer) == GetNUnitsInScriptGroup(idGroupFlagFactory)) then
    DebugMessage("Игрок "..numberPlayer.." удерживает завод");
    return 1;
else
    DebugMessage("Игрок "..numberPlayer.." не удерживает завод");
    DebugMessage("Игрок удерживает флагов: "..GetNUnitsInScriptGroup(idGroupFlagFactory, numberPlayer));
    return 0;
end;
end;

--Игрок может производить
function IsPlayerCanProduce(massivePlayersCanProduce, numberPlayer)
if (massivePlayersCanProduce[numberPlayer + 1] == 1) then
    DebugMessage("Игрок "..numberPlayer.." может производить");
    return 1;
else
    DebugMessage("Игрок "..numberPlayer.." не может производить");
    return 0;
end;
end;

--Сообщение для отладки
function DebugMessage(message)
if (GetIGlobalVar("IS_DEBUG", 1)) then
    DisplayTrace (message);
end;
end;

Плюсы:
Простой и надеюсь понятный скрипт
Процедура разбита на подпроцедуры для лучшей читаемости
Точно не будет нагружать карту т.к. проверки происходят 1 раз
Минусы:
Завод может работать только с флагами т.к. если объекта не существует, то и функция не сработает GetNUnitsInScriptGroup
Проверка не идет постоянно, нужно лишь удержать флаг на момент проверки для "выработки" продукта

Отредактировано Daniil1254 (2022-02-12 23:35:36)

+1

56

Daniil1254 написал(а):

А вот этот уже убивает выполнение скрипта

сам бы убивал за все эти бесполезные скобки в строке if (((number / multiple) == 1) or ((number / multiple) == -1))  %-)

предполагаете, что проблема в многобуквенных переменных в DisplayTrace? они работают... видимо не аккуратно загрузили функцию значениями, вот так точно работает:

DisplayTrace многобукв

function TextNM()
number=10;
multiple=10;
IsNumberMultiple(number, multiple);
end;
--Число кратно заданному
function IsNumberMultiple(number, multiple)
    if number/multiple==1 or number/multiple==-1 then
        DisplayTrace("Число %g кратно %g",number,multiple);
        return 1;
    else
        DisplayTrace("Число %g некратно %g",number,multiple);
        return 0;
    end;
    end;

Хорошего ГЗМ!

0

57

Не используйте ту (мою) функцию, я сделал по нормальному, эта работает, но с увеличением числа и использования маленького делителя скорость падает, но хватит пока такой

Вернуть остаток от деления/Определить кратно ли число делителю

--Вернуть остаток от деления (только с положительными числами)
function GetRemainderDivision(number, divider)
--DebugMessage ("Нахождение остатка деления "..number.." от "..divider);
if (divider == 0) then
    --DebugMessage ("На ноль делить нельзя");
    return -1;
end;
if (number < divider) then
    --DebugMessage ("Остаток от деления: "..number);
    return number;
end;
local d = divider;
while number >= divider do
    divider = divider + d;
end;
if (number == divider) then
    --DebugMessage ("Остаток от деления: "..0);
    return 0;
end;
--DebugMessage ("Остаток от деления: "..(number - (divider - d)));
return number - (divider - d);
end;

--Число кратно заданному
function IsNumberMultiple(number, multiple)
--DebugMessage ("Проверка кратности "..number.." и "..multiple);
if (GetRemainderDivision(number, multiple) == 0) then
    --DebugMessage ("Кратно");
    return 1;
else
    --DebugMessage ("Некратно");
    return 0;
end;
end;

Отредактировано Daniil1254 (2022-02-11 22:58:17)

0

58

Не могу понять как правильно пользоваться глобальным массивом
Задаю так
SetIGlobalVar("MASSIVE_SIDE", {0, 1, 2}); --Содержит информацию о принадлежности игроков к стороне
Но потом извлечь не пойму как, уже пробовал по разному
Это по идеи верный вариант GetIGlobalVar("MASSIVE_SIDE", {-2, -2, -2})[i], но он возвращает значение по умолчанию
То есть так GetIGlobalVar("MASSIVE_SIDE", {})[i] ничего не извлечется

Ну или может есть функция определяющая принадлежность игрока к стороне?

Отредактировано Daniil1254 (2022-02-12 17:07:45)

0

59

Daniil1254 написал(а):

local d = divider;
while number >= divider do
divider = divider + d;

в принципе и зайца в поле на коленях можно догнать при настойчивости :) ... но это уж слишком

правильный алгоритм
1. делим
2. частное записываем через SetIGlobalVar
3. достаем частное GetIGlobalVar (получаем ЦЕЛОЕ число), все что после запятой будет отброшено
4. отнимаем от делимого произведение делителя и частного, равно остаток от деления

Daniil1254 написал(а):

Не могу понять как правильно пользоваться глобальным массивом
Задаю так

так не "баботает" (как говорит мой замечательный внучок) ... записать можно лишь одно значение, а вот кол-во переменных не ограничено... так кто мешает записать для каждой стороны, свою?

очень похвально, что вы Daniil1254 занялись скриптописанием, но ЭТА тема для КУБИКОВ, которые наши уставшие картоделы должны легко и просто поставить в свой скрипт и получить что-то ощутимое для своих Гениальных Сценариев.... к чему им наши математические этюды, кратное, частное? ... им нужно чтобы взрывалось и летело, штамповалось и  запрещалось, атаковало и заряжалось... пожалуйста, в этой теме Готовые кубики... в теме Скрипты - вопросы и задачки по программированию, и прочие обсуждения. Спасибо

Хорошего ГЗМ!

+3

60

В наших миссиях часто используется рандом, однако, он бывает слишком рандомным  o.O .
Допустим, мы хотим сделать 5 разных случайных атак, которые не повторяются. Что делать в этом случае? Ответ прост! Сделать всё через наш любимый RandomInt(5)! А вот не так быстро. Оператору RandomInt(n) все равно, какие числа выдавать, у нас может повториться число "3" пять раз подряд, хоть и с маленьким шансом, и тогда у нас одна и та же атака запустится пять раз. Для решения этой задачи был разработан следующий экспериментальный кубик:

Уникальные случайные числа

RunScript("SetNumUnikInt",1000);

function SetNumUnikInt() -- инициализирует необходимые переменные, просто запустить один раз откуда-нибудь
local i,n;
n = 5; ------------------------------- единственный параметр, который нужно менять. Он отвечает за количество уникальных рандомных чисел
SetIGlobalVar("temp.NumUsedRandUnikInt",0);
SetIGlobalVar("temp.NumRandUnikInt",n);
for i = 1, n do
    SetIGlobalVar("temp.RandUnikInt"..i,0);
end;
Suicide();
end;

function GetRandomUnikInt(a) -- генератор случайных уникальных чисел
local i;
if GetIGlobalVar("temp.NumUsedRandUnikInt",0) < a then
    repeat
    i = RandomInt(a)+1;
    if GetIGlobalVar("temp.NumUsedRandUnikInt",0) == a then
        break;
    end;
    until GetIGlobalVar("temp.RandUnikInt"..i,0) == 0
    SetIGlobalVar("temp.RandUnikInt"..i,1);
    SetIGlobalVar("temp.NumUsedRandUnikInt", GetIGlobalVar("temp.NumUsedRandUnikInt",0) + 1);
    return i;
else
    Suicide();
end;
end;

Использовать его элементарно. Нужно запустить функцию с инициализацией переменных SetNumUnikInt() в любом месте, можно даже в Init, и скопировать кубик к себе.
Единственное, что можно в нем поменять, это переменную n, которая отвечает за количество таких уникальных случайных чисел.
Для получения числа просто вставляем такую длинную строчку в нужном нам месте: GetRandomUnikInt(GetIGlobalVar("temp.NumRandUnikInt",0)); По сути на её месте будет нужное нам число. Например a = GetRandomUnikInt(GetIGlobalVar("temp.NumRandUnikInt",0)); И в переменной "а" у нас окажется число от 1 до 5. При каждом последующем вызове число будет отличаться.
В итоге получим такую картину:
https://forumupload.ru/uploads/0000/38/bf/696/t517558.jpg

+3


Вы здесь » Союз | Union » Картостроение и скриптовка » Как перестать бояться и начать скриптить