Poprzedni temat «» Następny temat
Obliczenia w skryptach gry (ToBEx) - wprowadzenie
Autor Wiadomość
dradiel 
Dziecię Bhaala
Jeździec Shaundakula

Posty: 1713
Podziękowania: 799/111
Wysłany: 2013-11-30, 23:11   Obliczenia w skryptach gry (ToBEx) - wprowadzenie

Parę razy w dziale WoBG pisano o lawinie nieszczęsnych komunikatów wyświetlających się w czasie wyrównywania poziomów w wyniku działania moda Level1 NPCs. Przyszło mi więc do głowy zastosować możliwości, które daje rozszerzenie skryptowe, które wprowadził TobEx. Możliwość dokonywania obliczeń w skryptach gry daje ciekawe możliwości. Nie ma jednak na ten temat, nawet na shs, przynajmniej ja nie znalazłem, szerszych informacji, poza jednym wątkiem w dziale TobEx, w którym nie ma i tak zademonstrowanego działającego przykładu takiego bloku skryptu. Jako, że najczęściej najlepiej pewne zasady obrazuje przykład wrzucam taki blok. Poniższy kod jest równoważny temu co zawiera skrypt fjxpmooc.bcs o ponad 3000 linijkach kodu.
Dokonuje precyzyjnego wyrównania punktów doświadczenia oraz wyświetla zawsze tylko 2 komunikaty i robi to za pomocą tak niewielkiej ilości kodu. 3000 linijek kodu bez TobEx-a nie są w stanie nawet zbliżyć się do tego wyniku.

Na razie jest to tylko taki drobny test, pewnych rzeczy jeszcze do końca nie rozumiem, więc kod być może da się ulepszyć, jednak przykład i tak obrazuje jak niesamowite możliwości daje możliwość dokonywania obliczeń w skryptach.

Kod:
IF
    NextTriggerObject(LastSummonerOf(Myself))
    Assign("s[XP]",INT,1)
    Eval("#1",INT,1)
    NextTriggerObject(Player1)
    Assign("s[XP]",INT,2)
    Eval("#2",INT,2)
    !E(1,1)
THEN
    RESPONSE #100
        AssignFromObject("s[XP]",LastSummonerOf(Myself),INT,1)
        Assign("e[0 - #1]",INT,2)
        Eval("#2",INT,1)
        AddXpObject(LastSummonerOf(Myself),1)
        AssignFromObject("s[XP]",Player1,INT,1)
        Eval("#1",INT,1)
        AddXpObject(LastSummonerOf(Myself),1)
        Continue()
END

IF
    True()
THEN
    RESPONSE #100
        DestroySelf()
END


Oczywiście testowałem na WoBG, ale powinno to zadziałać na każdej instalacji posiadającej TobEx od wersji, która wprowadziła rozszerzenie do skryptów.
Komunikaty dotyczące doświadczenia wyświetlą się tylko dwa, ale ich też można się pozbyć, wykorzystując opcode dodający doświadczenie. Taki skrypt działający dużo sprawniej i precyzyjniej będzie miał tylko 300 linijek a nie 3000. Jeśli kogoś to będzie interesować to w następnym patchu w WoBG będzie można go sobie obejrzeć.

Dokumentacja ToBEx:
http://www.shsforums.net/...dder-reference/

Wątek poruszający powyższą tematykę:
http://www.shsforums.net/...anded-triggers/
Ostatnio zmieniony przez dradiel 2013-12-08, 06:18, w całości zmieniany 1 raz  
Podziękuj autorowi tego posta
 
 
Więcej szczegółów
Za tę wypowiedź podziękowali:
picollo, L`f, greegarak
picollo 

Posty: 578
Podziękowania: 64/98
Wysłany: 2013-12-03, 11:59   

Dradiel- świetna sprawa.
Boję się tylko, że w zbiorczym temacie to może zaginąć.
Mógłbyś założyć jakiś oddzielny temat dla tego posta? W formie w jakiej jest teraz mamy już mini tutorial. Ale jakbyś to ciut bardziej opisał i wrzucił jakiś pełnoprawny tutorial dotyczący obliczeń jakie umożliwił ToBEx, to chyba Cie ozłocę;)
_________________
był szalony jak stado zajęcy na wiosnę, kiedyś kazał nam ściąć cały zagajnik dębów, bo uroiło mu się, że go szpiegują... a potem doszedł do wniosku, że były jednak w porządku i rozkazał nam je pochować.
- czy wy wiecie ile czasu zajmuje zakopanie dębowego lasu?
Podziękuj autorowi tego posta
 
 
dradiel 
Dziecię Bhaala
Jeździec Shaundakula

Posty: 1713
Podziękowania: 799/111
Wysłany: 2013-12-03, 18:09   

Jeśli moderator wydzieli ten post do osobnego wątku to nie ma sprawy. Z czasem w miarę możliwości może uda się temat rozwinąć a przynajmniej na początek podlinkuję to co na ten temat jest dostępne w internecie.

W istocie, opis tego rozwiązania zasługuje na nowy temat, zwłaszcza jeśli w przyszłości ma szansę pojawić się jeszcze więcej o tym. Wydzielone. - L`f
Ostatnio zmieniony przez L`f 2013-12-03, 19:06, w całości zmieniany 2 razy  
Podziękuj autorowi tego posta
 
 
dradiel 
Dziecię Bhaala
Jeździec Shaundakula

Posty: 1713
Podziękowania: 799/111
Wysłany: 2014-03-05, 17:35   

Przy okazji przenoszenia Icewind Dale II natrafiłem na problem, który jak się okazuje, można rozwiązać tylko przy pomocy rozszerzeń skryptowych oferowanych przez TobEx (przynajmniej nie przyszło mi do głowy żadne inne standardowe rozwiązanie).

O co chodzi?
W IDII funkcjonuje coś takiego jak BitGlobal, przykładowy skrypt:

Kod:
IF
  Global("BattleSquareState","MYAREA",6)
  Global("PlayerWonSquare","LOCALS",0)
  BitGlobal("BattleSquareArenaScore","MYAREA",1,AND)
  BitGlobal("BattleSquareArenaScore","MYAREA",2,AND)
  BitGlobal("BattleSquareArenaScore","MYAREA",4,AND)
THEN
  RESPONSE #100
    FloatMessage(Myself,30947)
    SetGlobal("BattleSquareState","MYAREA",8)
END


Standardowo przy pomocy danej wartości zmiennej, jesteśmy w stanie kontrolować tylko jedną rzecz.
Jednak odpowiednio ustawiana wartość zmiennej, jak w tym przypadku "BattleSquareArenaScore" pozwala jedną wartością kontrolować wiele zdarzeń. W niektórych przypadkach, jak chociażby bitewne kwadraty jest to niezwykle przydatne, pozwalając w miarę prosty sposób zaprogramować ich działanie.

W powyższym przykładzie wartość "BattleSquareArenaScore" równa 7 kontroluje 3 pola z bitewnych kwadratów, ponieważ 7 to 4 + 2 + 1. Odpowiednio sumując liczby 1, 2, 4, 8, 16, 32, 64 itd. można osiągnąć skomplikowane zdarzenia, niezwykle trudne, o ile w ogóle możliwe do zrealizowania przy standardowym traktowaniu zmiennych.

Oczywiście silnik BGII nie posiada takiej funkcjonalności i jak na razie przypuszczam, odtworzenie bitewnych kwadratów nie byłoby możliwe lub ich działanie byłoby znacznie ograniczone. Na szczęście przyszedł z pomocą TobEX. Nie jest to proste rozwiązanie, jednak spełnia swoje zadanie.

Poniższy kod, to tak jakby silnik spełniający to samo zadanie co w IDII BitGlobal, jednak kod tego jest dużo bardziej skomplikowany niż odpowiednik z Icewind. Pewnie są niewielkie szanse, że kiedyś ktoś w swoim modzie będzie próbował coś takiego wykorzystać, jednak demonstruje możliwości rozszerzeń skryptowych do przeprowadzania obliczeń w skryptach. Może ktoś się skusi na próby zastosowania jakichś ciekawych rozwiązań w swoich modach.
Na chwilę obecną z testów wynika, że działa jak powinien, chociaż nie jest wykluczone, że coś jeszcze wyjdzie i będę musiał dokonać zmian. Dla zainteresowanych pełnym kontekstem sprawy w przyszłym patchu powinna pojawić się pierwsza wersja pliku 41parena.bcs, w którym jest on zawarty, choć nie jest pewne czy bitewne kwadraty do następnego patcha doczekają się pełnej funkcjonalności.


Kod:
IF
    Global("BattleSquareState","MYAREA",6)
    Global("reset_bloku_player","LOCALS",0)
THEN
    RESPONSE #100
        SetGlobal("reset_bloku_player","LOCALS",1)
        Assign("v[BattleSquarePlayerScore.MYAREA]",INT,1) //podpięcie do analizy zmiennej, która mnie interesuje
        Eval("#1",INT,1) //przepisanie jej wartości do zmiennej w warunku poniżej
        SetGlobal("BattleSquarePlayerScoreBit","MYAREA",1) //operuję na zmiennej zastępczej, ponieważ oryginalna w tym momencie nie może ulec zmianie
        Continue()
END

IF //kolejne bloku analizujące składowe bitowe od 1 do 256
    Global("playerbit256","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 256]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    GT(1,1) // na każdą składową bitową musi być po dwa warunki: GT i E, ponieważ nie istnieje warunek większy lub równy; dla wartości 1 wystarczy samo E
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-256) // w przypadku wystąpienia składowej bitowej trzeba usunąć ją ze zmiennej zastęczej, aby można było analizować pozostałe zmienne bitowe
        SetGlobal("playerbit256","MYAREA",1) //określenie, że wystąpiła zmienna bitowa 256
END

IF
    Global("playerbit256","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 256]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-256)
        SetGlobal("playerbit256","MYAREA",1)
END

IF
    Global("playerbit128","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 128]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    GT(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-128)
        SetGlobal("playerbit128","MYAREA",1)
END

IF
    Global("playerbit128","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 128]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-128)
        SetGlobal("playerbit128","MYAREA",1)
END

IF
    Global("playerbit64","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 64]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    GT(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-64)
        SetGlobal("playerbit64","MYAREA",1)
END

IF
    Global("playerbit64","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 64]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-64)
        SetGlobal("playerbit64","MYAREA",1)
END

IF
    Global("playerbit32","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 32]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    GT(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-32)
        SetGlobal("playerbit32","MYAREA",1)
END

IF
    Global("playerbit32","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 32]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-32)
        SetGlobal("playerbit32","MYAREA",1)
END

IF
    Global("playerbit16","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 16]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    GT(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-16)
        SetGlobal("playerbit16","MYAREA",1)
END

IF
    Global("playerbit16","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 16]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-16)
        SetGlobal("playerbit16","MYAREA",1)
END

IF
    Global("playerbit8","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 8]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    GT(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-8)
        SetGlobal("playerbit8","MYAREA",1)
END

IF
    Global("playerbit8","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 8]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-8)
        SetGlobal("playerbit8","MYAREA",1)
END

IF
    Global("playerbit4","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 4]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    GT(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-4)
        SetGlobal("playerbit4","MYAREA",1)
END

IF
    Global("playerbit4","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 4]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-4)
        SetGlobal("playerbit4","MYAREA",1)
END

IF
    Global("playerbit2","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 2]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    GT(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-2)
        SetGlobal("playerbit2","MYAREA",1)
END

IF
    Global("playerbit2","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 2]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-2)
        SetGlobal("playerbit2","MYAREA",1)
END

IF
    Global("playerbit1","MYAREA",0)
    Global("BattleSquareState","MYAREA",6)
    Assign("v[BattleSquarePlayerScoreBit.MYAREA]",INT,1)
    Assign("e[#1 - 1]",INT,2)
    Eval("#2",INT,1)
    Assign("c[0]",INT,3)
    Eval("#3",INT,2)
    E(1,1)
THEN
    RESPONSE #100
        IncrementGlobal("BattleSquarePlayerScoreBit","MYAREA",-1)
        SetGlobal("playerbit1","MYAREA",1)
END

IF //resetowanie warunków, aby po kolejnej walce dało się ponownie przeliczyć sytuację na planszy kwadratów.
    GlobalGT("BattleSquareState","MYAREA",6)
    Global("reset_bloku_player","LOCALS",1)
THEN
    RESPONSE #100
        SetGlobal("reset_bloku_player","LOCALS",0)
        SetGlobal("playerbit1","MYAREA",0)
        SetGlobal("playerbit2","MYAREA",0)
        SetGlobal("playerbit4","MYAREA",0)
        SetGlobal("playerbit8","MYAREA",0)
        SetGlobal("playerbit16","MYAREA",0)
        SetGlobal("playerbit32","MYAREA",0)
        SetGlobal("playerbit64","MYAREA",0)
        SetGlobal("playerbit128","MYAREA",0)
        SetGlobal("playerbit256","MYAREA",0)
        Continue()
END
Podziękuj autorowi tego posta
 
 
dradiel 
Dziecię Bhaala
Jeździec Shaundakula

Posty: 1713
Podziękowania: 799/111
Wysłany: 2014-07-14, 21:04   

Kolejny, może tym razem drobny, ale też ciekawy przykład zastosowania rozszerzeń TobeX-a.

Klasztor Czarnego Kruka, spora ilość mnichów, z którymi można walczyć. Doszedłem do wniosku, że nie będę każdej odmiany pliku .cre mnichów specjalnie modyfikował. Pobrałem do skryptu informację o poziomie mnicha i na tej podstawie przydzielam cechy stałe, jak i liczbę możliwych "zaklęć" do rzucenia w czasie walki.

Kod:
IF
    Assign("s[LEVEL]",INT,1) //pobranie informacji o poziomie
    Assign("e[#1 / 5]",INT,2) //przeliczenie, że za każde 5 poziomów przyznaje jedną regenerację
    Eval("#2",INT,1) //podpięcie wartości do zmiennej lokalnej, która będzie licznikiem
    GlobalLT("regeneracja_licznik","LOCALS",1) //ta zmienna dla mnicha o np. 15 poziomie ma wartość 3
THEN
    RESPONSE #100
        ApplySpellRES("tg#regem",Myself) // Regeneracja mnicha
        IncrementGlobal("regeneracja_licznik","LOCALS",1)
END


W taki sam sposób, mnich będzie używał zdolności "ogłuszające uderzenie", z tym, że jako otrzymuje jedno na poziom, to nie trzeba go już przeliczać.

Kod:
IF
    Range(NearestEnemyOf(Myself),5)
    !GlobalTimerNotExpired("timer_rzucanie_czarow","LOCALS")
    !GlobalTimerNotExpired("ogluszajace_uderzenie","LOCALS")
    !GlobalTimerNotExpired("ogluszajace_uderzenie","MYAREA")
    Allegiance(Myself,ENEMY)
    See([PC])
    !CheckStat(Myself,1,OGLUSZAJACE_UDERZENIE)
    Assign("s[LEVEL]",INT,1)
    Eval("#1",INT,1)
    GlobalLT("ogluszajace_uderzenie_licznik","LOCALS",1)
THEN


Ciekawą rzeczą, którą wprowadza też TobeX jest możliwość definiowania swoich własnych "stanów":
!CheckStat(Myself,1,OGLUSZAJACE_UDERZENIE)

Dzięki wprowadzonemu opcodowi 318, można dużo lepiej kontrolować, kto pod wpływem jakiego zaklęcia jest i dzięki temu lepiej sterować rzucaniem zaklęć przez NPC-e.

W przypadku, gdyby kogoś to bardziej zainteresowało to, powyższe przykłady są z pliku mnich.bcs, który będzie dostępny w WoBG od patcha 1.38, który będzie kiedyś tam :)
Podziękuj autorowi tego posta
 
 
Wyświetl posty z ostatnich:   
Odpowiedz do tematu
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Możesz ściągać załączniki na tym forum
Dodaj temat do Ulubionych
Wersja do druku

Skocz do:  
Powered by phpBB modified by Przemo © 2003 phpBB Group