SAIL - Podwójny Laser

Gotowe kody SAIL'a, informacje na temat moddingu, itd.

Moderator: zoNE

Post Reply
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:

SAIL - Podwójny Laser

Post by zoNE »

0dd1 wrote: Sat Aug 12, 2017 11:05 pm 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;
Author: 0dd1
Topic: https://forum.original-war.net/viewtopi ... 51&p=53183
Last edited by zoNE on Sun Feb 11, 2018 5:18 pm, edited 1 time in total.
Post Reply