Skocz do zawartości
  • 0

Zaliczanie śmierci moba do zmiennej po zginięciu od ognia, spadnięciu z wysokości itp.


Pytanie

Witam. Mam prosty skrypt dodający 1 punkt do zmiennej graczowi za każde zabicie Zombie. Problem polega na tym, że jeśli przykładowo gracz uderzy moba mieczem z fire aspect, a mob zginie od ognia, to nie jest to postrzegane jako zabicie moba i końcowo nie jest dodany punkt do zmiennej. Czy wie ktoś w jaki sposób to rozwiązać? Pozdrawiam

on death of a zombie:
	add 1 to {zombie::%uuid of attacker%}

 

7 odpowiedzi na to pytanie

Rekomendowane odpowiedzi

  • 1
28 minut temu, nnisu napisał:

Witam. Mam prosty skrypt dodający 1 punkt do zmiennej graczowi za każde zabicie Zombie. Problem polega na tym, że jeśli przykładowo gracz uderzy moba mieczem z fire aspect, a mob zginie od ognia, to nie jest to postrzegane jako zabicie moba i końcowo nie jest dodany punkt do zmiennej. Czy wie ktoś w jaki sposób to rozwiązać? Pozdrawiam

on death of a zombie:
	add 1 to {zombie::%uuid of attacker%}

 

Najprościej będzie to rozwiązać za pomocą wyrażenia 'last attacker of %entity%'. Należy mieć na uwadze to, że te wyrażenie zwróci nazwę gracza, nie jego UUID.
Dodam, że powinien Pan sprawdzać na początku listeneru zdarzenia czy ostatnio atakujący byt jest graczem. Dzięki temu unikamy zapisu zmiennych dla bytów innych niż gracze (wszystkie byty (nawet przedmioty) posiadają UUID, chociaż głównie należy martwić się tutaj żywymi bytami), na przykład żelazne golemy czy szkielety. One też jak najbardziej są w stanie zabić zombie.

on death of a zombie:
	last attacker of victim is a player
	# Dalszy kod...

Oczywiście może (i myślę, że byłoby wskazane) sprawdzanie czasu od ostatniego uderzenia, ale samo użycie powyższego wyrażenia do podstawowych zastosowań jest wystarczające. Gdyby jednak Pan potrzebował coś takiego, mogę zaproponować jak można taki kod napisać.

Pozdrawiam.

  • 0
4 godziny temu, Kormic napisał:

Najprościej będzie to rozwiązać za pomocą wyrażenia 'last attacker of %entity%'. Należy mieć na uwadze to, że te wyrażenie zwróci nazwę gracza, nie jego UUID.
Dodam, że powinien Pan sprawdzać na początku listeneru zdarzenia czy ostatnio atakujący byt jest graczem. Dzięki temu unikamy zapisu zmiennych dla bytów innych niż gracze (wszystkie byty (nawet przedmioty) posiadają UUID, chociaż głównie należy martwić się tutaj żywymi bytami), na przykład żelazne golemy czy szkielety. One też jak najbardziej są w stanie zabić zombie.

on death of a zombie:
	last attacker of victim is a player
	# Dalszy kod...

Oczywiście może (i myślę, że byłoby wskazane) sprawdzanie czasu od ostatniego uderzenia, ale samo użycie powyższego wyrażenia do podstawowych zastosowań jest wystarczające. Gdyby jednak Pan potrzebował coś takiego, mogę zaproponować jak można taki kod napisać.

Pozdrawiam.

Dziękuję bardzo za pomoc. Nie potrzebuję sprawdzania czasu od ostatniego uderzenia, skrypt będzie mi potrzebny do skryptu na proste, codzienne questy, także nawet jeśli zombie zginie po dłuższym czasie i śmierć zostanie zaliczona graczowi, to nic się nie stanie.  Natomiast byłbym bardzo wdzięczny gdyby nakierował mnie Pan mniej więcej na to jak można użyć wyrażenia 'last attacker of %entity%'. Rozumiem, że zwraca on ostatni byt, który zaatakował moba, natomiast nie do końca wiem jak użyć tego w taki sposób, aby do zmiennej gracza, który zabił moba naliczała się wartość. Z góry dziękuję za pomoc.

Pozdrawiam

  • 1
2 godziny temu, nnisu napisał:

Dziękuję bardzo za pomoc. Nie potrzebuję sprawdzania czasu od ostatniego uderzenia, skrypt będzie mi potrzebny do skryptu na proste, codzienne questy, także nawet jeśli zombie zginie po dłuższym czasie i śmierć zostanie zaliczona graczowi, to nic się nie stanie.  Natomiast byłbym bardzo wdzięczny gdyby nakierował mnie Pan mniej więcej na to jak można użyć wyrażenia 'last attacker of %entity%'. Rozumiem, że zwraca on ostatni byt, który zaatakował moba, natomiast nie do końca wiem jak użyć tego w taki sposób, aby do zmiennej gracza, który zabił moba naliczała się wartość. Z góry dziękuję za pomoc.

Pozdrawiam

No dobrze, już podpowiadam. Problem z użyciem tego wyrażenia jest taki, ze zwracana przez nie wartość jest typu 'Object', a więc może to być tak właściwie wszystko. Wynika to z faktu, iż ostatnio atakującym może być dowolny byt, a nawet blok, na przykład dozownik (ang. dispenser), który wystrzeliwuje strzały.

Bezpieczniejszą opcją będzie zamiana wartości wyrażenia 'last attacker of %entity%' na typ tekstowy, aby później nakazać Skriptowi interpretację go jako gracza offline.
Dlaczego gracz offline, a nie online? Powody ku temu są dwa:

  1. Gracz może wyjść z serwera zanim zombie umrze. Może tak być w przypadku nadania efektu obumierania, podpalenia, itd.
  2. Powód mniej oczywisty to to, że wyrażenie '%string% parsed as player' ma pewną mało znaną, a znaczącą wadę. W przypadku parse'owania jako gracza online wystarczy początek nazwy gracza, aby Skript "wygenerował" nam obiekt gracza. Natomiast jeśli używamy '[...] parsed as offline player', musimy podać dokładnie nazwę gracza.
    Podam przykład wykorzystujący moją nazwę.
    "Kormic" parsed as player # Zwróci obiekt gracza o nazwie "Kormic", o ile jest on na serwerze
    "Kor" parsed as player # Zwróci obiekt gracza o nazwie "Kormic", o ile jest on na serwerze
    
    "Kormic" parsed as offline player # Zwróci obiekt gracza o nazwie "Kormic" niezależnie od tego czy jest i był kiedykolwiek na serwerze
    "Kor" parsed as offline player # Zwróci obiekt gracza o nazwie "Kor" niezależnie od tego czy jest i był kiedykolwiek na serwerze

    W tej sytuacji pojawia się pytanie "Co jeśli poprosimy o obiekt gracza online o nazwie "Kor", podczas gdy na serwerze są gracze "Kor" i "Kormic"? Którego gracza otrzymamy?".
    Dlatego też w mojej ocenie bezpieczniejszy jest 'parsed as offline player', bo musimy podać dokładną nazwę.

Poniżej udostępniam Panu fragment kodu, dzięki któremu w zmiennej {_player} przechowywany jest obiekt gracza offline (offline - może, ale nie musi być online). Wtedy wystarczy użyć 'uuid of {_player}' tam gdzie trzeba.

# [...]
last attacker of victim is a player
set {_player} to "%last attacker of victim%" parsed as offline player
# [...]

Alternatywnie, można spróbować jak poniżej. Nie mam  pewności czy poniższy sposób zadziała poprawnie, ale spróbować nie zaszkodzi.

# [...]
last attacker of victim is a player
set {_uuid} to uuid of last attacker of victim
# [...]

Pozdrawiam.

Edytowane przez Kormic
  • 0
2 godziny temu, Kormic napisał:

No dobrze, już podpowiadam. Problem z użyciem tego wyrażenia jest taki, ze zwracana przez nie wartość jest typu 'Object', a więc może to być tak właściwie wszystko. Wynika to z faktu, iż ostatnio atakującym może być dowolny byt, a nawet blok, na przykład dozownik (ang. dispenser), który wystrzeliwuje strzały.

Bezpieczniejszą opcją będzie zamiana wartości wyrażenia 'last attacker of %entity%' na typ tekstowy, aby później nakazać Skriptowi interpretację go jako gracza offline.
Dlaczego gracz offline, a nie online? Powody ku temu są dwa:

  1. Gracz może wyjść z serwera zanim zombie umrze. Może tak być w przypadku nadania efektu obumierania, podpalenia, itd.
  2. Powód mniej oczywisty to to, że wyrażenie '%string% parsed as player' ma pewną mało znaną, a znaczącą wadę. W przypadku parse'owania jako gracza online wystarczy początek nazwy gracza, aby Skript "wygenerował" nam obiekt gracza. Natomiast jeśli używamy '[...] parsed as offline player', musimy podać dokładnie nazwę gracza.
    Podam przykład wykorzystujący moją nazwę.
    "Kormic" parsed as player # Zwróci obiekt gracza o nazwie "Kormic", o ile jest on na serwerze
    "Kor" parsed as player # Zwróci obiekt gracza o nazwie "Kormic", o ile jest on na serwerze
    
    "Kormic" parsed as offline player # Zwróci obiekt gracza o nazwie "Kormic" niezależnie od tego czy jest i był kiedykolwiek na serwerze
    "Kor" parsed as offline player # Zwróci obiekt gracza o nazwie "Kor" niezależnie od tego czy jest i był kiedykolwiek na serwerze

    W tej sytuacji pojawia się pytanie "Co jeśli poprosimy o obiekt gracza online o nazwie "Kor", podczas gdy na serwerze są gracze "Kor" i "Kormic"? Którego gracza otrzymamy?".
    Dlatego też w mojej ocenie bezpieczniejszy jest 'parsed as offline player', bo musimy podać dokładną nazwę.

Poniżej udostępniam Panu fragment kodu, dzięki któremu w zmiennej {_player} przechowywany jest obiekt gracza offline (offline - może, ale nie musi być online). Wtedy wystarczy użyć 'uuid of {_player}' tam gdzie trzeba.

# [...]
last attacker of victim is a player
set {_player} to "%last attacker of victim%" parsed as offline player
# [...]

Alternatywnie, można spróbować jak poniżej. Nie mam  pewności czy poniższy sposób zadziała poprawnie, ale spróbować nie zaszkodzi.

# [...]
last attacker of victim is a player
set {_uuid} to uuid of last attacker of victim
# [...]

Pozdrawiam.

Dziękuję bardzo za pomoc. Nie chcę cały czas prosić o pomoc, ale niestety, albo ja nie potrafię tego użyć, a główkuję nad tym już od 2 godzin, albo coś tu nie działa. Zrobiłem prosty test:

on death of a zombie:
	set {player} to "%last attacker of victim%"
	broadcast "%{player}%"

Nie wiem czy chodzi o event "on death of a zombie", czy powinno się to używać w innych eventach, czy jak, ale w tym przypadku jeśli zabiję zombie normalnie, wysyła się broadcast z moim nickiem, czyli to działa. Natomiast gdy uderzę zombie parę razy mieczem z fire aspect, i pozostawię go na spłonięcie, on zginie, po czym wysyła się broadcast "<none>". Także do zmiennej nie jest zapisywana nazwa gracza który ostatni uderzył zombie. Próbowałem to rozgryźć na wiele sposobów (używałem i parse as offline player i parse as player, używałem zmiennych tymczasowych, zwykłych, grupowych, choć pewnie nie ma do żadnego znaczenia chciałem przetestować to na wiele sposobów) i na prawdę nie mam pojęcia jak to rozwiązać. Nie wiem czy ja coś robię źle. Jeśli to nie problem to prosiłbym o jakąś podpowiedź. Dziękuję bardzo za każdą pomoc. Pozdrawiam

  • 1
28 minut temu, nnisu napisał:

Dziękuję bardzo za pomoc. Nie chcę cały czas prosić o pomoc, ale niestety, albo ja nie potrafię tego użyć, a główkuję nad tym już od 2 godzin, albo coś tu nie działa. Zrobiłem prosty test:

on death of a zombie:
	set {player} to "%last attacker of victim%"
	broadcast "%{player}%"

Nie wiem czy chodzi o event "on death of a zombie", czy powinno się to używać w innych eventach, czy jak, ale w tym przypadku jeśli zabiję zombie normalnie, wysyła się broadcast z moim nickiem, czyli to działa. Natomiast gdy uderzę zombie parę razy mieczem z fire aspect, i pozostawię go na spłonięcie, on zginie, po czym wysyła się broadcast "<none>". Także do zmiennej nie jest zapisywana nazwa gracza który ostatni uderzył zombie. Próbowałem to rozgryźć na wiele sposobów (używałem i parse as offline player i parse as player, używałem zmiennych tymczasowych, zwykłych, grupowych, choć pewnie nie ma do żadnego znaczenia chciałem przetestować to na wiele sposobów) i na prawdę nie mam pojęcia jak to rozwiązać. Nie wiem czy ja coś robię źle. Jeśli to nie problem to prosiłbym o jakąś podpowiedź. Dziękuję bardzo za każdą pomoc. Pozdrawiam

Z początku myślałem, że Pan może mieć jakiś problem ze Skriptem, ale sprawdziłem przed chwilą działanie wyrażenia 'last attacker of %entity%'. Rzeczywiście jest tak jak Pan mówi - w przypadku śmierci od obrażeń innych niż zadane bezpośrednio przez dowolny byt, wyrażenie te zwraca "<none>".
Sprawdziłem kod źródłowy Skripta i dowiedziałem się kilku ciekawych rzeczy.

https://github.com/SkriptLang/Skript/blob/7fc699e17299763523942d99524216480d426295/src/main/java/ch/njol/skript/expressions/ExprLastAttacker.java#L59

Warto zwrócić uwagę na użycie metody 'getLastDamageCause()', która (jak nazwa wskazuje) zwraca przyczynę ostatnio zadanych obrażeń, a właściwie to całe zdarzenie, które było powiązane z zadanymi ostatnio obrażeniami. Co więcej, poniższa klasa odpowiedzialna za wyrażenie 'attacker' przewiduje jedynie zdarzenie 'EntityDamageByEntityEvent'. Nawet kod od zdarzenia 'EntityDamageByBlockEvent' (np. gdy dozownik trafi w zombie strzałą) jest objęty komentarzem, a więc w przypadku śmierci od strzały wystrzelonej z dozownika również uświadczylibyśmy na czacie '<none>'.

https://github.com/SkriptLang/Skript/blob/7fc699e17299763523942d99524216480d426295/src/main/java/ch/njol/skript/expressions/ExprAttacker.java#L78

Na końcu metody 'get()' w klasie ExprAttacker można zauważyć 'return null'. Ponieważ obrażenia od ognia nie są przewidziane w żadnym z warunków tej metody, otrzymujemy w rezultacie niemiło widziane '<none>'.

Skoro już poznaliśmy źródło nieporozumienia, podpowiem Panu jak można rozwiązać ten problem.

W mojej ocenie najprostszym wyjściem z tej sytuacji będzie użycie 'metadata'. Jak dokumentacja mówi, są to informacje przechowywane w rozmaitych metadata holderach (byty, bloki, itd.) do momentu restartu serwera, ale na Pana potrzeby wydaje mi się, że to będzie wystarczające.
No dobrze, jak więc użyć metadata w Pana przypadku? Jest to bardzo proste. Dla przykładu ustawimy wartość metadata "lastAttacker" jako byt, który był odpowiedzialny za zadanie obrażeń. Następnie, będziemy mogli odczytywać jej wartość gdy będzie to potrzebne. Pokażę na przykładzie poniżej.

W listenerze zdarzenia 'on damage' należy sprawdzić czy atakujący jest graczem. Jeśli tak, ustawiamy wartość znacznika (tagu) metadata "lastAttacker" na atakującego (w tym przypadku wiemy, że to jest gracz, ponieważ zweryfikowaliśmy to warunkiem w linijce powyżej).

# [...]
attacker is a player
set metadata tag "lastAttacker" of victim to attacker
# [...]

Następnie, w listenerze zdarzenia 'on death of a zombie' sprawdzamy czy metadata tag "lastAttacker" posiada wartość (warunek 'is set'). Możemy to zrobić bezpośrednio, albo też możemy zapisać jej wartość do zmiennej i sprawdzić czy zmienna przechowuje jakąkolwiek wartość. Ja pokażę drugi sposób, gdyż jest schludniejszy - unikamy podwójnego użycia tego samego wyrażenia.

# [...]
set {_player} to metadata tag "lastAttacker" of victim
{_player} is set
# [...]

Jeżeli warunek w powyższym fragmencie kodu zostanie spełniony, możemy być pewni, że ofiara posiada zapisaną w sobie informację o ostatnio atakującym graczu. Wystarczy wtedy użyć 'uuid of {_player}' i wszystko powinno być działać jak należy.

Oczywiście może Pan rozszerzyć działanie powyższych kodów na wszystkie byty tak, aby na przykład owca zapisywała informację o tym, że wilk ją zaatakował. Wtedy kod nieco się skomplikuje i niewykluczone, że trzeba będzie użyć więcej metadata tagów.

Zastanawiające jest jedynie to co jeśli zombie umrze po wyjściu gracza z serwera. Co prawda Skript w tej sytuacji powinien "przemianować" zapisaną informację o online player na informację o offline player. Warto jednak to przetestować, chociaż tę kwestię myślę, że mogę pozostawić Panu do własnego wglądu.

Gdyby jeszcze miał Pan jakieś pytania lub wątpliwości, śmiało.

Pozdrawiam.

  • 0
42 minuty temu, Kormic napisał:

Z początku myślałem, że Pan może mieć jakiś problem ze Skriptem, ale sprawdziłem przed chwilą działanie wyrażenia 'last attacker of %entity%'. Rzeczywiście jest tak jak Pan mówi - w przypadku śmierci od obrażeń innych niż zadane bezpośrednio przez dowolny byt, wyrażenie te zwraca "<none>".
Sprawdziłem kod źródłowy Skripta i dowiedziałem się kilku ciekawych rzeczy.

https://github.com/SkriptLang/Skript/blob/7fc699e17299763523942d99524216480d426295/src/main/java/ch/njol/skript/expressions/ExprLastAttacker.java#L59

Warto zwrócić uwagę na użycie metody 'getLastDamageCause()', która (jak nazwa wskazuje) zwraca przyczynę ostatnio zadanych obrażeń, a właściwie to całe zdarzenie, które było powiązane z zadanymi ostatnio obrażeniami. Co więcej, poniższa klasa odpowiedzialna za wyrażenie 'attacker' przewiduje jedynie zdarzenie 'EntityDamageByEntityEvent'. Nawet kod od zdarzenia 'EntityDamageByBlockEvent' (np. gdy dozownik trafi w zombie strzałą) jest objęty komentarzem, a więc w przypadku śmierci od strzały wystrzelonej z dozownika również uświadczylibyśmy na czacie '<none>'.

https://github.com/SkriptLang/Skript/blob/7fc699e17299763523942d99524216480d426295/src/main/java/ch/njol/skript/expressions/ExprAttacker.java#L78

Na końcu metody 'get()' w klasie ExprAttacker można zauważyć 'return null'. Ponieważ obrażenia od ognia nie są przewidziane w żadnym z warunków tej metody, otrzymujemy w rezultacie niemiło widziane '<none>'.

Skoro już poznaliśmy źródło nieporozumienia, podpowiem Panu jak można rozwiązać ten problem.

W mojej ocenie najprostszym wyjściem z tej sytuacji będzie użycie 'metadata'. Jak dokumentacja mówi, są to informacje przechowywane w rozmaitych metadata holderach (byty, bloki, itd.) do momentu restartu serwera, ale na Pana potrzeby wydaje mi się, że to będzie wystarczające.
No dobrze, jak więc użyć metadata w Pana przypadku? Jest to bardzo proste. Dla przykładu ustawimy wartość metadata "lastAttacker" jako byt, który był odpowiedzialny za zadanie obrażeń. Następnie, będziemy mogli odczytywać jej wartość gdy będzie to potrzebne. Pokażę na przykładzie poniżej.

W listenerze zdarzenia 'on damage' należy sprawdzić czy atakujący jest graczem. Jeśli tak, ustawiamy wartość znacznika (tagu) metadata "lastAttacker" na atakującego (w tym przypadku wiemy, że to jest gracz, ponieważ zweryfikowaliśmy to warunkiem w linijce powyżej).

# [...]
attacker is a player
set metadata tag "lastAttacker" of victim to attacker
# [...]

Następnie, w listenerze zdarzenia 'on death of a zombie' sprawdzamy czy metadata tag "lastAttacker" posiada wartość (warunek 'is set'). Możemy to zrobić bezpośrednio, albo też możemy zapisać jej wartość do zmiennej i sprawdzić czy zmienna przechowuje jakąkolwiek wartość. Ja pokażę drugi sposób, gdyż jest schludniejszy - unikamy podwójnego użycia tego samego wyrażenia.

# [...]
set {_player} to metadata tag "lastAttacker" of victim
{_player} is set
# [...]

Jeżeli warunek w powyższym fragmencie kodu zostanie spełniony, możemy być pewni, że ofiara posiada zapisaną w sobie informację o ostatnio atakującym graczu. Wystarczy wtedy użyć 'uuid of {_player}' i wszystko powinno być działać jak należy.

Oczywiście może Pan rozszerzyć działanie powyższych kodów na wszystkie byty tak, aby na przykład owca zapisywała informację o tym, że wilk ją zaatakował. Wtedy kod nieco się skomplikuje i niewykluczone, że trzeba będzie użyć więcej metadata tagów.

Zastanawiające jest jedynie to co jeśli zombie umrze po wyjściu gracza z serwera. Co prawda Skript w tej sytuacji powinien "przemianować" zapisaną informację o online player na informację o offline player. Warto jednak to przetestować, chociaż tę kwestię myślę, że mogę pozostawić Panu do własnego wglądu.

Gdyby jeszcze miał Pan jakieś pytania lub wątpliwości, śmiało.

Pozdrawiam.

Działa. Nie wiem jak mam Panu dziękować. Przede wszystkim jestem zszokowany poziomem Pana wiedzy, na prawdę :) Dziękuję najmocniej. Co do umierania zombie po wyjściu gracza z serwera - tak jak Pan mówi, Skript zamienia informację o online player na offline player. Normalnie dodaje się wartość do zmiennej gracza nawet po wyjściu z serwera. Dziękuję bardzo jeszcze raz.

Pozdrawiam serdecznie :) 

Nieaktywny
Ten temat został zamknięty. Brak możliwości dodania odpowiedzi.
  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...