Sail: Podwójny Laser

Wszelkie pytania na temat SAIL'a i modowania OW.
Post Reply
User avatar
0dd1
ArCamp Developer
Posts: 334
Joined: Tue Jul 01, 2014 3:01 pm

Sail: Podwójny Laser

Post by 0dd1 »

Funkcja w założeniu ma działać jak ComAttackUnit dla podwójnych laserów. Jednak z racji na ich wyjątkowość musi być używana bez przerwy, przez cały czas trwania ataku. Dodatkowo zadziała na całą listę laserów i wrogów - funkcja sama dobiera lasery do celów.

Podanie Area przy użyciu funkcji jest opcjonalne - oznacza obszar do którego lasery mają NIE wchodzić, jeśli akurat jest taka potrzeba.

Ostatnia wartość oznacza preferowaną odległość laserów od ich celu. Dozwolone wartości: 0 - lasery otaczają cel jak najciaśniej, 1 - pośrednia odległość (w większości przypadków najbardziej rozsądna), 2 - lasery będą rozstawiać się podczas ataku jak najszerzej.

Code: Select all

Function DoubleLaserAttack(LaserList, AllTargets, Area, val);
var Lasers, LaserGroups, L1, L2, Target, temp_target_list, TargetX, TargetY;
var hex_list1, hex_list2, hex1, hex2, temp_hex, choosen_hexes, temp_list_x, temp_list_y, chosen_list;
var i, j, un, temp, temp_list, dist, dist1, dist2, common_hex;
var dir0_x, dir0_y, dir1_x, dir1_y, dir2_x, dir2_y, dir3_x, dir3_y, dir4_x, dir4_y, dir5_x, dir5_y, dir6_x, dir6_y, dir7_x, dir7_y, dir8_x, dir8_y, dir9_x, dir9_y, dir10_x, dir10_y, dir11_x, dir11_y;
begin
     if AllTargets <= 0 then
        exit;

     temp_list = UnitFilter(LaserList, [f_not,[f_weapon,us_double_laser]]);

     if temp_list > 0 then                         
        ComAttackUnit(temp_list, AllTargets[1]);   //Jednostki inne niż podwójne lasery po prostu atakują pierwszy cel z listy

     Lasers = UnitFilter(LaserList, [f_weapon,us_double_laser]);

     if Lasers < 2 then
     begin                                         
          ComAttackUnit(Lasers, AllTargets[1]);    //To samo dotyczy pojedyńczego lasera
          exit;
     end
     else
         begin
              LaserGroups = [];

              //Dobieranie laserów w pary. Jeśli zostanie jeden ekstra to będzie robił to samo co drugi laser w ostatniej parze
              while Lasers > 1 do
              begin
                   temp = [Lasers[1], Lasers[2]];
                   Lasers = Lasers diff temp;

                   if Lasers = 1 then
                      temp = temp ^ Lasers[1];

                   LaserGroups = LaserGroups ^ [temp];
              end;
         end;

     if val < 0 then
        val = 0;

     if val > 2 then
        val = 2;


     //Przy każdym celu (T) przyjmuje się zestaw hexów które tworzą kilka okręgów wokój jego pozycji. Składa się to z 7 teoretycznych hexów odchodzących w prostej linii od celu, w każdym z 12 kierónków
     //Dir0 tutaj to to samo co kierunek 0 w edytorze, Dir1 idzie pomiędzy kierunkiem 0 i 1 w edytorze, Dir2 odpowiada kierunkowi 1 i tak dalej
     // *  *  *  *  *
     //   * * * * *
     //     *****
     // * * * T * * *
     //     *****
     //   * * * * *
     // *  *  *  *  *

     //Poniżej coordynaty względem pozycji celu
     Dir0_X = [0, 0, 0, 0, 0, 0, 0];    Dir0_Y = [-3, -5, -7, -9, -11, -13, -15]; Dir1_X = [2, 3, 4, 5, 6, 7, 8];     Dir1_Y = [-2, -3, -4, -5, -6, -7, -8];
     Dir2_X = [3, 5, 7, 9, 11, 13, 15]; Dir2_Y = [0, 0, 0, 0, 0, 0, 0];           Dir3_X = [4, 6, 8, 10, 12, 14, 16]; Dir3_Y = [2, 3, 4, 5, 6, 7, 8];
     Dir4_X = [4, 5, 7, 9, 11, 13, 15]; Dir4_Y = [4, 5, 7, 9, 11, 13, 15];        Dir5_X = [2, 3, 4, 5, 6, 7, 8];     Dir5_Y = [4, 6, 8, 10, 12, 14, 16];
     Dir6_X = [0, 0, 0, 0, 0, 0, 0];    Dir6_Y = [3, 5, 7, 9, 11, 13, 15];        Dir7_X = [-2, -3, -4, -5, -6, -7, -8]; Dir7_Y = [2, 3, 4, 5, 6, 7, 8];
     Dir8_X = [-3, -5, -7, -9, -11, -13, -15]; Dir8_Y = [0, 0, 0, 0, 0, 0, 0];    Dir9_X = [-4, -6, -8, -10, -12, -14, -16]; Dir9_Y = [-2, -3, -4, -5, -6, -7, -8];
     Dir10_X = [-3, -5, -7, -9, -11, -13, -15]; Dir10_Y = [-3, -5, -7, -9, -11, -13, -15]; Dir11_X = [-2, -3, -4, -5, -6, -7, -8]; Dir11_Y = [-4, -6, -8, -10, -12, -14, -16];

     temp_list_x = [dir0_x, dir1_x, dir2_x, dir3_x, dir4_x, dir5_x, dir6_x, dir7_x, dir8_x, dir9_x, dir10_x, dir11_x];
     temp_list_y = [dir0_y, dir1_y, dir2_y, dir3_y, dir4_y, dir5_y, dir6_y, dir7_y, dir8_y, dir9_y, dir10_y, dir11_y];

     temp_target_list = 0;

     for un in LaserGroups do
     begin
          common_hex = [(GetX(un[1]) + GetX(un[2]))/2, (GetY(un[1]) + GetY(un[2]))/2];
          temp_list = [];

          if temp_target_list = 0 then
             temp_target_list = AllTargets;

          dist = 999;

          //Wybieranie najbliższego celu dla każdej pary laserów
          for i in temp_target_list do
          begin
               dist1 = GetDistUnits(i, un[1]);
               dist2 = GetDistUnits(i, un[2]);

               if dist1 > dist2 then
                  temp = dist1
               else temp = dist2;

               //Dodatkowy próg (+ 3) zapobiega zbyt częstej zmianie celu. Inaczej mogą zmieniać sobie cel gdy tylko minimalnie się ruszą
               if temp + 3 < dist then
               begin
                    dist = temp;
                    Target = i;
               end;
          end;

          temp_target_list = temp_target_list diff Target;

          TargetX = GetX(Target);
          TargetY = GetY(Target);

          hex_list1 = [];
          hex_list2 = [];

          //Wybieranie pierwszego dostępnego hexu z każdego kierunku, aby otrzymać pojedyńczy okrąg z hexów
          //Sprawdzane są w parach - jeśli jakiś kierunek nie ma żadnego dostępnego hexu, kierunek po przeciwnej stronie też się nie liczy
          for i = 1 to 6 do
          begin
               hex1 = [];
               hex2 = [];

               hex_list1 = hex_list1 ^ [hex1];
               hex_list2 = hex_list2 ^ [hex2];

               //Priorytet: najbliższy, środkowy lub najdalszy dystans, zależnie od wybranej wartości
               case val of
                    0: temp_list = [1,2,3,4,5,6,7];
                    1: temp_list = [4,5,3,6,2,7,1];
                    else
                        temp_list = [7,6,5,4,3,2,1];
               end;

               //Dostępny hex to: wolny i znajdujący się na mapie, nie będący w wybranym Area, nie będący stromym zboczem, ani terenem typu: don't enter, don't enter water, don't enter rock
               for j in temp_list do
               begin
                    temp_hex = [TargetX + temp_list_x[i][j], TargetY + temp_list_y[i][j]];

                    if not ValidHex(temp_hex[1], temp_hex[2]) or ( HexInfo(temp_hex[1], temp_hex[2]) > 0 and not HexInfo(temp_hex[1], temp_hex[2]) in un ) then
                       continue;

                    if Area > 0 then
                       if InArea(temp_hex[1], temp_hex[2], Area) then
                          continue;

                    if GetHexInfo(temp_hex[1], temp_hex[2])[3] in [40,41,42,43,44,45,48,49,50,51,52,53] or GetHexInfo(temp_hex[1], temp_hex[2])[6] in [3,4,6] then
                       continue;

                    hex1 = temp_hex; //Hex wybrany
                    break;
               end;

               if hex1 = [] then   
                  continue;

               //Powtórzenie tego samego dla kierunków po drugiej stronie celu
               for j in temp_list do
               begin
                    temp_hex = [TargetX + temp_list_x[i+6][j], TargetY + temp_list_y[i+6][j]];

                    if not ValidHex(temp_hex[1], temp_hex[2]) or ( HexInfo(temp_hex[1], temp_hex[2]) > 0 and not HexInfo(temp_hex[1], temp_hex[2]) in un ) then
                       continue;

                    if Area > 0 then
                       if InArea(temp_hex[1], temp_hex[2], Area) then
                          continue;

                    if GetHexInfo(temp_hex[1], temp_hex[2])[3] in [40,41,42,43,44,45,48,49,50,51,52,53] or GetHexInfo(temp_hex[1], temp_hex[2])[6] in [3,4,6] then
                       continue;

                    hex2 = temp_hex;
                    break;
               end;

               if hex2 = [] then
                  continue;

               //Te dwa zestawy razem tworzą pojenyńczy okrąg z hexów wokół celu
               hex_list1 = Replace(hex_list1, i, hex1);
               hex_list2 = Replace(hex_list2, i, hex2);
          end;

          //Jeśli nie wybrano żadnych hexów, lasery po prostu podjadą do celu
          if (hex_list1 diff 0) = 0 then
          begin
               ComMoveUnit(un, Target);
               exit;
          end;

          //Dwa zestawy tych samych hexów w przeciwnej kolejności. Po jednym dla każdego laseru.
          hex_list1 = hex_list1 ^ hex_list2;
          hex_list2 = hex_list2 ^ hex_list1;

          temp_list = [];
          j = [1,2,3,4,5,6,7,8,9,10,11,12];

          //W obrębie ustalonego okręgu: wybieranie najbliższej pary hexów zależnie od pozycji obu laserów
          //Aby potem porównać odległości od pozostałych hexów w odpowieniej kolejności
          for i in j do
              temp_list = temp_list ^ GetDistXY(common_hex[1],common_hex[2], TargetX + temp_list_x[i][5],TargetY + temp_list_y[i][5]);

          i = WorstFromListByList(j,temp_list);


          case i of
               1,7: temp_list = [4,5,6,1,2,3];
               2,8: temp_list = [5,6,1,2,3,4];
               3,9: temp_list = [6,1,2,3,4,5];
               4,10: temp_list = [1,2,3,4,5,6];
               5,11: temp_list = [2,3,4,5,6,1];
               6,12: temp_list = [3,4,5,6,1,2];
          end;                                 

          dist = 999;


          //2 tryby ataku: 1- Jeśli lasery są oddalone od celu to zbliżają się do swojej najbliższej pary hexów
          //               2- Jeśli już są na pozycji to powinny zacząć równocześnie przemieszczać się po okręgu. Dzięki temu mogą uniknąć trochę pocisków wroga
          for i in temp_list do
          begin
               if hex_list1[i] = [] then
                  continue;

               hex1 = hex_list1[i];
               hex2 = hex_list2[i];

               //Przy wybieraniu najbliższej pary hexów, dobrze jest najpierw ustalić który laser jest bliżej którego hexu
               if GetDistUnitXY(un[1], hex1[1], hex1[2]) < GetDistUnitXY(un[2], hex1[1], hex1[2]) + 3 then
               begin
                    L1 = un[1];
                    L2 = un[2];
               end
               else
               begin
                    L1 = un[2];
                    L2 = un[1];
               end;

               dist1 = GetDistUnitXY(L1, hex1[1], hex1[2]);
               dist2 = GetDistUnitXY(L2, hex2[1], hex2[2]); 


               //Atak 2: wybierane są trzy kolejne hexy w okręgu aby lasery były w ciągłym ruchu
               if dist1 < [3,4,6][val+1] and dist2 < [3,4,6][val+1] then
               begin
                    choosen_hexes = [];

                    for j = 1 to 3 do
                        if i + j > hex_list1 then
                           choosen_hexes = choosen_hexes ^ [hex_list1[i+j - hex_list1], hex_list2[i+j - hex_list1]]
                        else
                            choosen_hexes = choosen_hexes ^ [hex_list1[i+j], hex_list2[i+j]];
                    break;
               end;


               if dist1 > dist2 then
                  temp = dist1
               else
                   temp = dist2;

               //Atak1 : najbliższa para hexów
               if (temp + [6,8,10][val+1]) < dist then
               begin
                    dist = temp;
                    choosen_hexes = [hex1, hex2];
               end;
          end;

          //Jeśli zostanie jeden ekstra to będzie robił to samo co drugi laser w ostatniej parze
          if un > 2 then
             L2 = L2 ^ un[3];

          //Jeśli nie wybrano żadnych hexów, lasery po prostu podjadą do celu
          if choosen_hexes[1] = [] then
          begin
               ComMoveUnit([L1,L2], Target);
               exit;
          end;


          //I w końcu, polecenie samego ruchu do wybranych hexów
          ComMoveXY(L1, choosen_hexes[1][1],choosen_hexes[1][2]);
          ComMoveXY(L2, choosen_hexes[2][1],choosen_hexes[2][2]);

          if choosen_hexes > 2 then
             for i = 3 to choosen_hexes do
                 if choosen_hexes[i] > [] then
                    if i in [3,5] then
                       AddComMoveXY(L1, choosen_hexes[i][1],choosen_hexes[i][2])
                    else
                        AddComMoveXY(L2, choosen_hexes[i][1],choosen_hexes[i][2]);

     end;
end; 

Mała prezentacja (starszej wersji) poniżej. Kod ataku to dosłownie coś takiego:

Code: Select all

every 0$1 do
begin
DoubleLaserAttack(BlueTeam, RedTeam, area);
enable;
end;
Last edited by 0dd1 on Sun Feb 11, 2018 2:31 pm, edited 4 times in total.
Do it!
User avatar
zoNE
The Great Uniter & Site Administrator
The Great Uniter & Site Administrator
Posts: 2059
Joined: Fri Feb 17, 2006 3:44 pm
Location: Poland
Contact:

Re: Sail: Podwójny Laser

Post by zoNE »

Fajne, fajne :P. Nie zagłębiałem się w kod, więc nie sprawdzałem jak dokładnie działa, ale tak patrząc na filmik, bym zrobił jeszcze drugą, do której bym dodał priorytety celów oraz skupianie się na celach, bo tak, jak ComAttackUnit troszkę się gubią i działają chaotycznie jedynie atakując w drodze do celu. By można zrobić tak, aby otaczały konkretne wybrane cele priorytetowe w kodzie (według ważności celu) i na nich się skupiały, by w drodze do określonego miejsca najpierw zniszczyć cele priorytetowe lub cele blokujące do nich dostęp, a dopiero później szły dalej. Mogłaby z tego fajna funkcja wyjść pod AI.
Last edited by zoNE on Sat Aug 12, 2017 11:47 pm, edited 3 times in total.
User avatar
0dd1
ArCamp Developer
Posts: 334
Joined: Tue Jul 01, 2014 3:01 pm

Re: Sail: Podwójny Laser

Post by 0dd1 »

Lasery się gubią przy ataku bo wszystko jest w ciągłym ruchu, a nie ma prostego sposobu aby sprawdzić jak "dostępny" jest cel, poza porównywaniem odległości w prostej linii. Teraz to trochę usprawniłem i jest odrobinę stabilniej ale wciąż potrafią zachowywać się dziwnie.

Priorytety celów to raczej indywidualna kwestia, to trzeba dopasować do konkretnej sytuacji. Po to funkcja jest tak napisana żeby mogła poradzić sobie z każdą ilością jednostek, żeby można było samemu wybrać lasery i ich cele. Na przykład na filmiku widać jak atakują bazę z Am14. Tam specjalnie ustawiłem żeby najpierw atakowali wieżyczki, a dopiero potem inne jednostki. Dodatkowo funkcja celowo była użyta tylko na jednym celu naraz, aby lasery skupiły swój atak. Normalnie lepiej jest jak każda para ma osobny cel, ale tutaj miały utrudnione zadanie i w tym trybie o wiele szybciej by zostały zniszczone.

A co do samego AI, to już stworzyłem coś takiego w misji 13 Arabskiej Kampanii. Właściwie cała misja polega na tym że jednostki wroga spawnują się, jadą po wytyczonej ścieżce w górę mapy, i atakują jednostki gracza które zobaczą, a jak te zostaną zniszczone albo im uciekną, to jadą dalej. Teraz zastosowałem to samo w ostatniej misji, gdzie bazy wroga wysyłają co jakiś czas oddział na patrol po mapie, a funkcja ataku laserów powstała właśnie po to żeby AI mogło użyć podwójnych laserów przeciw graczowi.
Do it!
User avatar
zoNE
The Great Uniter & Site Administrator
The Great Uniter & Site Administrator
Posts: 2059
Joined: Fri Feb 17, 2006 3:44 pm
Location: Poland
Contact:

Re: Sail: Podwójny Laser

Post by zoNE »

Ogólnie fajna funkcja, w grze czegoś takiego właśnie brakowało - praktycznego wykorzystania DL przez komputer.
User avatar
Serpent
Soldier level 10
Soldier level 10
Estonia
Posts: 4175
Joined: Tue Jul 07, 2009 9:13 pm
Location: Polska - EuroStan ZSRE
Contact:

Re: Sail: Podwójny Laser

Post by Serpent »

Mała uwaga:
Podanie Area przy użyciu funkcji jest opcjonalne - oznacza obszar do którego lasery mają NIE wchodzić, czyli niedostępne hexy jak strome zbocza albo głęboka woda. Nie da się tego określić z poziomu Saila, jedyny sposób to ręczne zaznaczenie wszystkich takich hexów na mapie.
Ostatnio poprosiłem Stukacza który dodał funkcję sprawdzającą hex'a pod kątem jego właściwości. Myślę że można jej użyć w tym kodzie zamiast wyznaczać aree z góry :)
Epickie teksty:
Marek1906: jak zrobic aby sail był zielony?
Kvantovy: Wszystko normalne, wszystko w koło było dziwne
Kvantovy:: To jest fajne, że to nie jest takie głupie
Kvantovy:: remove sos from kanapeczka
Kvantovy:: zdarzają się rzezy które sie filozofom nie śniły
Cenwen: problemem jest gejostwo
"Taki z niego fizyk jak ze mnie baletnica" - Profesor Scholtze o Kvantovym.
JAKBYŁ BYM CZECHEM TO BYM ROZŁOŻYŁ NAMIOT ~Kvanciak
User avatar
0dd1
ArCamp Developer
Posts: 334
Joined: Tue Jul 01, 2014 3:01 pm

Re: Sail: Podwójny Laser

Post by 0dd1 »

W końcu się za to wziąłem. Teraz funkcja sama może zignorować niedostępne hexy ale i tak zostawiłem to Area. W niektórych sytuacjach może się przydać bo nie ma się innej kontroli nad tym gdzie lasery dokładnie pojadą.

Wypadałoby też uaktualnić to co jest w archiwum.
Do it!
User avatar
zoNE
The Great Uniter & Site Administrator
The Great Uniter & Site Administrator
Posts: 2059
Joined: Fri Feb 17, 2006 3:44 pm
Location: Poland
Contact:

Re: Sail: Podwójny Laser

Post by zoNE »

Zaktualizowane.
Post Reply