Problem z monologiem 14709 56

O temacie

Autor Orion

Zaczęty 10.05.2013 roku

Wyświetleń 14709

Odpowiedzi 56

Lehona

Lehona

Użytkownicy
posty196
Propsy190
  • Użytkownicy
Well you can get around the stack problem by using Ikarus, but maybe not everyone is willing to use Ikarus (for whatever reason).

I'm pretty sure you can just use category 0, that's at least my experience, although I haven't done it recently, that will make your function simpler. Also Daedalus has a stack size of 1024, usually that is big enough to clear your inventory (which is capped at 1024 stacks as well), who the fuck has 800 different items anyways?
 
Unless specified otherwise, my posts are always about Gothic 2 Night of the Raven.

Orion

Orion

Użytkownicy
posty41
  • Użytkownicy

Orion

Problem z monologiem
#41 2013-06-05, 18:43(Ostatnia zmiana: 2013-06-05, 18:48)
Dzięki. Mam tylko co do tego kilka pytań. (Jestem początkujący,i chciałbym się nauczyć pisać skrypty, a z takim się jeszcze nie spotkałem.)
Co do:
func void Npc_ClearInventory (var c_npc npc)
{
    Npc_ClearInventoryLoop(npc, 0);
}
To npc w (var c_npc npc) to argument, więc służy tylko do wywołania funkcji? Czyli równie dobrze mogłoby to być "self", albo w ogóle jakieś przypadkowe słowo?
W  Npc_ClearInventoryLoop(npc, 0); npc to argument, więc musi być tak jak wyżej, a 0 co oznacza? Wydaje mi się, że jest to cyfra, która wynika z drugiej części skryptu.

A co do drugiej części:
func void Npc_ClearInventoryLoop (var c_npc npc, var int category)
{
    int amount = Npc_GetInvItemBySlot (npc, category, 0);
    if (amount)
    {
            NPC_RemoveInvItems (npc, Hlp_GetInstanceID (item), amount);
            Npc_ClearInventoryLoop(npc, category);
    }
    else if (category < INV_CAT_MAX-1)
    {
            Npc_ClearInventoryLoop(npc, category+1);
    };
};

To npc po "var c_npc" jest argumentem? Musi być tak samo jak wyżej?
Category to zmienna liczbowa, którą gdzieś tu opisujemy w "int amount"?
Co właściwie robi linijka "int amount = Npc_GetInvItemBySlot (npc, category, 0);"? Bo rozumiem, że tam gdzie jest RemoveInvItems amount odpowiada za liczbę przedmiotów usuwanych, ale tam wyżej przy if i int? Mamy je jakoś wpisać w miejsce amount? No i przy else wygląda to tak, że jest kilka category, ale gdzie one zostają opisane?
Wiem, że ten post może wywołać napad śmiechu na tym forum, albo jakąś salwę zasłużonej krytyki, ale chciałbym zrozumieć funkcje raz a dobrze, bo w każdym tutorialu czytałem tylko co można dzięki jakiejś danej zrobić, co mi niewiele dało.

Edit: Thanks Lehona for a tip. I'm not a great programmer, 'couse my knowledge about it is just this forum, and my very weak skills, so I don't know if i can use Ikarus on my own.
 

inż. Avallach

inż. Avallach

Administrator
posty7661
Propsy5239
NagrodyV
ProfesjaProgramista
  • Administrator

inż. Avallach
Administrator

Problem z monologiem
#42 2013-06-05, 19:15(Ostatnia zmiana: 2013-06-05, 19:36)
Nijak nie zrozumiałeś ;p
To co podałem to definicje funkcji. Określają jak mają być one wywoływane i co ma się dziać kiedy zostanie to zrobione. Treść pisze się zależnie od tego co ma się dziać. Zmienne / argumenty można nazywać dowolnie, pod warunkiem że nie są to już istniejące identyfikatory globalne. "Self" takim jest, więc nie można tego użyć ponownie.
Wszystko co przy wywoływaniu funkcji jest w nawiasie po jej nazwie to argumenty.
Spróbuj ogarnąć troszeczkę dowolnego języka programowania to będzie ci łatwiej.

Z tego co pisze Lehona (mi też tak się wydawało, ale nie byłem pewien), argument category funkcji zewnętrznej NPC_RemoveInvItems i tak nie działa, więc całość można uprościć:
func void Npc_ClearInventoryLoop (var c_npc npc) //kolejno: co ma zwracać funkcja (nic), jak ma się nazywać, jakie ma mieć argumenty (jeden typu c_npc który nazwałem "npc)
{
        int amount = Npc_GetInvItemBySlot (npc, 0, 0); //stworzenie zmiennej liczbowej i zapisanie w niej ile jest itemów w pierwszym slocie ekwipunku. drugie zero powinno wybierać kategorię eq, ale w funkcji jest błąd i nic nie robi
        if (amount) //jeśli ilość nie jest równa zero
        {
                NPC_RemoveInvItems (npc, Hlp_GetInstanceID (item), amount); //usuń przedmioty. argumenty to: komu (npc), co (Hlp_GetInstanceID (item) - dość skomplikowana sprawa, jak chcesz mogę wyjaśnić dlaczego akurat takie coś), ile (amount)
                Npc_ClearInventoryLoop(npc); //skoro tym razem coś usunąłeś, to spróbuj zrobić to jeszcze raz. w ten sposób powstaje pętla która przerwie się dopiero kiedy warunek nie będzie spełniony (czyli eq będzie pusty)
        }
};
Po znakach "//" są komentarze, czyli opis dla programisty pomagający zrozumieć kod i nie wpływający na jego działanie.
Kiedy chcesz opróżnić ekwipunek bohatera, wywołujesz to następująco:
Npc_ClearInventoryLoop(hero);
@Lehona: Well, you are probably right :D
I guess that with argument zero (such category doesn't exist, there are only 1-8) function indeed takes whole inventory into account, so such additional  loop is not needed.
It's goot to know the size of parser stack, sometimes it was hard to guess if some loop can overflow it or not. In case of inventory items such risk is definitely negligible.

Lehona

Lehona

Użytkownicy
posty196
Propsy190
  • Użytkownicy
Remember that the way Gothic is using the stack is a bit... obscure. Additional to an Integer, most of the time an additional 1-byte token is pushed to indicate what kind of data is stored (integer, variable, string...). This does not happen if an instance is pushed onto the stack (think of them as "raw", while all other data has a type). I assume this plays a part in using the stack, so you'll be able to use approximately 800-900 integers on the stack. Also note that nesting functions (as is done in a recursion) doesn't actually affect the stack, return addresses are not saved on the stack but somewhere else, only parameters etc. that are on the stack while eventually stack up.
And remember Daedalus doesn't have true local variables unless you use LeGo which provides a way to use local variables, so all recursive solutions must be approached with a grain of salt.
 
Unless specified otherwise, my posts are always about Gothic 2 Night of the Raven.

Orion

Orion

Użytkownicy
posty41
  • Użytkownicy
Ten sposób działa, ale gdy wpisywałem dwa przedmioty. Teraz skrypt wygląda tak:

var int amountweapon;
var int amountarmor;
var int amountmagic;
var int amountartifacts;
var int amountfood;
var int amountpotions;
var int amountwritten;
var int amountmisc;
func void B_ClearTradeInv (var C_NPC ctrd)
{
amountweapon = Npc_GetInvItemBySlot (ctrd, 1, 0);
amountarmor = Npc_GetInvItemBySlot (ctrd, 2, 0);
amountmagic = Npc_GetInvItemBySlot (ctrd, 3, 0);
amountartifacts = Npc_GetInvItemBySlot (ctrd, 4, 0);
amountfood = Npc_GetInvItemBySlot (ctrd, 5, 0);
amountpotions = Npc_GetInvItemBySlot (ctrd, 6, 0);
amountwritten = Npc_GetInvItemBySlot (ctrd, 7, 0);
amountmisc = Npc_GetInvItemBySlot (ctrd, 8, 0);
    if (amountweapon >= 1)
    {
    NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItMw_1H_Sword_Broad_03), 1);
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItMw_2H_Sword_01), 1);
B_ClearTradeInv(ctrd);
};
if (amountarmor >= 1)
{
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (Vlk_Armor_L), 1);
B_ClearTradeInv(ctrd);
};
if (amountmagic >= 1)
{
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItArScrollLight), 1);
B_ClearTradeInv(ctrd);
};
if (amountartifacts >= 1)
{
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (Amulett_der_Macht), 1);
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (Ring_der_Erleuchtung), 1);
B_ClearTradeInv(ctrd);
};
if (amountfood >= 1)
{
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItFo_Plants_mountainmoos_01), 1);
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItFo_Plants_Berrys_01), 1);
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItFo_Plants_Flameberry_01), 1);
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItFoRice), 1);
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItFoBooze), 1);
B_ClearTradeInv(ctrd);
};
if (amountpotions >= 1)
{
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItFo_Potion_Health_02), 1);
B_ClearTradeInv(ctrd);
};
if (amountwritten >= 1)
{
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (Die_Gruft), 1);
B_ClearTradeInv(ctrd);
};
if (amountmisc >= 1)
{
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItMiNugget), 1);
NPC_RemoveInvItems (ctrd, Hlp_GetInstanceID (ItKeLockpick), 1);
B_ClearTradeInv(ctrd);
};
};

Napisałem kilka zmiennych na górze, bo tego chyba wymagała ta funkcja, a te wszystkie przedmioty znajdują się w inwentarzu npc gdy on umiera.
Gra wywala do pulpitu, i nie wyświetla żadnych komunikatów podczas śmierci npc, więc chyba silnik nie wyrobił z czymś takim. No i tak na uboczu zmieniłem npc na ctrd, bo w innym skrypcie mam trd, ale to nie jest istotne.
 

Sawik

Sawik

Moderator działu
Rebel
posty4772
Propsy3197
ProfesjaNierób
  • Moderator działu
  • Rebel
Av napisał Ci już funkcję, a Ty ją przepisałeś... gorzej :F
 
Życzę wam seksu analnego po stronie biernej.
Dropbox +500 mb na start
LowPoly
Wykonanie modelu niskopoligonowego to sztuka kompromisu. Nie jest to jedynie uproszczenie modelu wysokopoligonowego, ale głęboka modyfikacja oraz podejmowanie decyzji często zmieniających wygląd pierwotny obiektu, tak by przy najmniejszej ilości trójkątów uzyskać jak najwierniej odwzorowany kształt oryginału. Nie można też zapomnieć o tym iż musi nadal wyglądać przekonywająco i tak balansować by uzyskać efekt optymalny.

Podstawowym założeniem jest, że model nie powinien mieć zbędnych, niewidocznych dla gracza detali włączonych w geometrie. Większość obiektów jakie znajdują się w grze powinna prezentować się najlepiej z odległości około 3-5 metrów. Wszelkie detale, które zanikają, wydają się płaskie lub zlewają się z bryłą modelu należy uznać za zbędne i pozostawić je na normal mapie.

Fakt, iż gracz będzie w stanie podejść bliżej do obiektu i zobaczyć go z mniejszej niż 3m odległości nie powinno stanowić większego problemu, gdyż większą rolę odgrywają wtedy tekstury oraz dodatkowy detal zależny od materiału obiektu. To właśnie kompromis między wydajnością, a szczegółowością otoczenia.

Detal, którego nie widać z 3-5 metrów nie powinnien istnieć w geometrii modelu.
Krawędzie znajdujące się blisko siebie, które zlewają się z większej odległości należy uprościć do wspólnej płaszczyzny

Orion

Orion

Użytkownicy
posty41
  • Użytkownicy

Orion

Problem z monologiem
#46 2013-06-05, 22:43(Ostatnia zmiana: 2013-06-06, 07:01)
Gdy korzystałem z tamtej, to usuwało tylko przedmioty z pierwszego slotu ekwipunku (czyli broń), a dodawałem tam inne przedmioty. Poza tym musiałem napisać kilka zmiennych amount, bo każdy slot potrzebuje innej.
 


Orion

Orion

Użytkownicy
posty41
  • Użytkownicy

Orion

Problem z monologiem
#48 2013-06-06, 14:56(Ostatnia zmiana: 2013-06-06, 15:02)
Nie bardzo wiem jak zrobić aby tamta działała, więc napisałem coś takiego:
var int amount;
func void B_ClearTradeInvLoop (var c_npc npc, var int category)
{
    amount = Npc_GetInvItemBySlot (npc, category, 0);
    if (amount >= 1)
    {
            NPC_RemoveInvItems (npc, Hlp_GetInstanceID (ItMiNugget), 1);
            B_ClearTradeInvLoop(npc, category);
    }
    else if (category < INV_CAT_MAX-1)
    {
            B_ClearTradeInvLoop(npc, category+1);
    };
};



func void B_ClearTradeInv (var c_npc npc)
{
    B_ClearTradeInvLoop(npc, 0);
};

Ale to też wyłącza grę podczas zabijania npc.
 

inż. Avallach

inż. Avallach

Administrator
posty7661
Propsy5239
NagrodyV
ProfesjaProgramista
  • Administrator

inż. Avallach
Administrator

Problem z monologiem
#49 2013-06-06, 15:08(Ostatnia zmiana: 2013-06-06, 15:19)
Mam wrażenie że od początku tematu twoja filozofia postępowania ze skryptami totalnie się nie zmieniła. Mogę tylko z przykrością zacytować swojego posta z poprzedniej strony:
Mój skrypt nie działa, próbowałem go naprawić, ale czego bym nie zmienił, i tak wyskakuje błąd.
Wow, debugowanie metodą brute-force. Jestem pod wrażeniem.
Statystycznie rzecz biorąc jak będziesz robił to dość długo to w końcu ci się uda, może nawet po drodze wyjdzie ci parę dzieł Shakespeare#msg1085475a.
Twoje modyfikacje są pozbawione sensu. Nie dość że próbujesz naprawiać ten kod najwyraźniej nie rozumiejąc co robisz, to na dodatek próbujesz naprawić coś co jest poprawne (i tylko to psujesz).
To co zrobiłeś powoduje że usuwane są jedynie bryłki rudy, więc rekurencja się zapętla w nieskończoność, w końcu jest przepełniany stos i gra crashuje. Po prostu przeczytaj co piszę i zrób to, dałem ci gotowca (czego normalnie nigdy nie robię, ale tu uznałem że problem nie jest taki całkiem oczywisty).

Gotowa funkcja. Nie musisz jej rozumieć. Nie edytuj jej. Po prostu wstaw gdzieś gdzie będzie parsowana przed twoimi skryptami.
func void Npc_ClearInventory (var c_npc npc)
{
        Npc_ClearInventoryLoop(npc, 0);
}

func void Npc_ClearInventoryLoop (var c_npc npc, var int category)
{
        int amount = Npc_GetInvItemBySlot (npc, category, 0);
        if (amount>0)
        {
                NPC_RemoveInvItems (npc, Hlp_GetInstanceID (item), amount);
                Npc_ClearInventoryLoop(npc, category);
        }
        else if (category < INV_CAT_MAX-1)
        {
                Npc_ClearInventoryLoop(npc, category+1);
        };
};

Tak wywołujesz (identycznie jak w g2nk):
Npc_ClearInventory (self);Zamiast self możesz wstawić dowolną inną zmienną typu c_npc.

Orion

Orion

Użytkownicy
posty41
  • Użytkownicy
Zrobiłem tak jak pisałeś, wstawiłem ten skrypt, jednak było tam kilka "literówek". Wygląda to tak:
var int amount;
func void Npc_ClearInventoryLoop (var c_npc npc, var int category)
{
    amount = Npc_GetInvItemBySlot (npc, category, 0);
    if (amount>0)
    {
            NPC_RemoveInvItems (npc, Hlp_GetInstanceID (item), amount);
            Npc_ClearInventoryLoop(npc, category);
    }
    else if (category < INV_CAT_MAX-1)
    {
            Npc_ClearInventoryLoop(npc, category+1);
    };
};

func void Npc_ClearInventory (var c_npc npc)
{
    Npc_ClearInventoryLoop(npc, 0);
};
Ale to w ogóle nie działa, nie usuwa żadnego przedmiotu. Choć pewnie dlatego, że znowu coś w skrypcie zepsułem.
 

Sawik

Sawik

Moderator działu
Rebel
posty4772
Propsy3197
ProfesjaNierób
  • Moderator działu
  • Rebel
Dobra, odkąd przeczytałem pierwszy skrypt się nad tym zastanawiam, być może zabrzmię jak idiota, nic dziwnego zresztą, ale... skąd gothic ma wiedzieć o który "item" chodzi? Npc_GetInvItemBySlot jest zapisywane w "amount", nie w item.
Identyfikator jest intem, więc... może to o to chodzi?
 
Życzę wam seksu analnego po stronie biernej.
Dropbox +500 mb na start
LowPoly
Wykonanie modelu niskopoligonowego to sztuka kompromisu. Nie jest to jedynie uproszczenie modelu wysokopoligonowego, ale głęboka modyfikacja oraz podejmowanie decyzji często zmieniających wygląd pierwotny obiektu, tak by przy najmniejszej ilości trójkątów uzyskać jak najwierniej odwzorowany kształt oryginału. Nie można też zapomnieć o tym iż musi nadal wyglądać przekonywająco i tak balansować by uzyskać efekt optymalny.

Podstawowym założeniem jest, że model nie powinien mieć zbędnych, niewidocznych dla gracza detali włączonych w geometrie. Większość obiektów jakie znajdują się w grze powinna prezentować się najlepiej z odległości około 3-5 metrów. Wszelkie detale, które zanikają, wydają się płaskie lub zlewają się z bryłą modelu należy uznać za zbędne i pozostawić je na normal mapie.

Fakt, iż gracz będzie w stanie podejść bliżej do obiektu i zobaczyć go z mniejszej niż 3m odległości nie powinno stanowić większego problemu, gdyż większą rolę odgrywają wtedy tekstury oraz dodatkowy detal zależny od materiału obiektu. To właśnie kompromis między wydajnością, a szczegółowością otoczenia.

Detal, którego nie widać z 3-5 metrów nie powinnien istnieć w geometrii modelu.
Krawędzie znajdujące się blisko siebie, które zlewają się z większej odległości należy uprościć do wspólnej płaszczyzny

inż. Avallach

inż. Avallach

Administrator
posty7661
Propsy5239
NagrodyV
ProfesjaProgramista
  • Administrator

inż. Avallach
Administrator

Problem z monologiem
#52 2013-06-06, 22:18(Ostatnia zmiana: 2013-06-06, 22:24)
Jakbym miał zgadywać, to źle wywołujesz funkcję. Pokaż jak i gdzie to robisz i napisz na kim chcesz żeby zadziałała.

Zła była linijka "amout", zainicjowałem zmienną jakby to była Java/C#, fakt, to mój błąd (brakowało "var" i rozbicia na dwie linijki). Ale ty z kolei niepotrzebnie dałeś ją jako zmienną globalną, poza funkcją, to nie ma sensu. Powinna być wewnątrz (jako zmienna pseudolokalna):
func void Npc_ClearInventoryLoop (var c_npc npc, var int category)
{
        print(ConcatStrings("Czyszczenie eq: ", npc.name);
        var int amount;
        amount = Npc_GetInvItemBySlot (npc, category, 0);
        print(ConcatStrings(item.name, IntToString(amount));
        if (amount>0)
        {
                NPC_RemoveInvItems (npc, Hlp_GetInstanceID (item), amount);
                Npc_ClearInventoryLoop(npc, category);
        }
        else if (category < INV_CAT_MAX-1)
        {
                print(ConcatStrings("Zmiana kategorii na: ", IntToString(category+1));
                Npc_ClearInventoryLoop(npc, category+1);
        };
};

func void Npc_ClearInventory (var c_npc npc)
{
        Npc_ClearInventoryLoop(npc, 0);
};
Teraz nic nie zepsułeś. Trzeba szukać przyczyny gdzie indziej. Oprócz tego co napisałem na początku posta, problem może tkwić w działaniu funkcji Gothica. W kodzie dodałem parę printów. Napisz co się wyświetli na ekranie po odpaleniu, ewentualnie potem je usuń.
Ewentualnie jak jest chętny ktoś z większym doświadczeniem i odpalający Gothica to też mógłby spróbować.

@Sawik: item to zmienna obiektowa analogiczna w działaniu do m.in. self i other. Silnik dynamicznie przydziela jej zawartość zależnie od kontekstu. Wywołanie funkcji Npc_GetInvItemBySlot ustawia ją na znaleziony item. PB preferuje to jako bezpieczniejszą alternatywę dla zwracania obiektów bezpośrednio przez funkcje.

Orion

Orion

Użytkownicy
posty41
  • Użytkownicy
Wkleiłem ten z printami, (i dodałem przy tym dwa ")", bo zabrakło ich, co pokazał mi zSpy), no i dalej nic nie usuwa. Poza tym, nie wyświetlił mi się żaden napis.
Teraz trochę o tym, jak wywołuję funkcję. (Wzorowałem, a raczej przepisałem ją z Gothic II, i działa, bo wcześniejsze funkcje normalnie wywoływało, czyli gdy usuwałem tylko jeden przedmiot na sprawdzenie).

func void B_GiveTradeInv (var C_NPC self)
{
var C_NPC Trd_Sharky; Trd_Sharky = Hlp_GetNpc (ORG_843_Sharky);

if Hlp_GetInstanceID (self) == Hlp_GetInstanceID (Trd_Sharky) {B_GiveTradeInv_Sharky (self);}; //B_GiveTradeInv_Sharky - mam tam wypisane, które przedmioty Sharky dostaje, i to działa, bo gdy z nim handluję, (a właśnie przy handlu wywołuję B_GiveTradeInv (self)) to ma je w inwentarzu.

if (Npc_IsInState (self, ZS_Dead))
{
if  Hlp_GetInstanceID (self) == Hlp_GetInstanceID (Trd_Sharky) {Npc_ClearInventory (self);};   //no i tu ją wywołuję
};
};
 

inż. Avallach

inż. Avallach

Administrator
posty7661
Propsy5239
NagrodyV
ProfesjaProgramista
  • Administrator

inż. Avallach
Administrator

Problem z monologiem
#54 2013-06-06, 22:53(Ostatnia zmiana: 2013-06-06, 23:20)
Skoro nie pojawia się ŻADEN napis, to znaczy że po prostu funkcja nie jest wywoływana. Swoją drogą dziwne że mogłeś nazwać argument funkcji "self", skoro taki identyfikator jest już użyty.

@Lehona: thanks, it's good to know :D

Lehona

Lehona

Użytkownicy
posty196
Propsy190
  • Użytkownicy
Just for confirmation: In Gothic 2 your script works perfectly fine. Either it's different in Gothic 1 (which I can't test, either) or Orion is using it wrong.
 
Unless specified otherwise, my posts are always about Gothic 2 Night of the Raven.

Orion

Orion

Użytkownicy
posty41
  • Użytkownicy

Orion

Problem z monologiem
#56 2013-06-06, 23:06(Ostatnia zmiana: 2013-06-06, 23:29)
Dodawanie przedmiotów działa, a użyłem self, bo tak było w GII. Nie wiem dlaczego funkcja usuwania ekwipunku nagle nie chce się wywołać, bo wcześniej normalnie była uruchamiana podczas zabijania npc.

Edit:
Brak wyświetlenia napisu nie jest winą Gothica I, bo zmieniłem na zwyczajne
print("Czyszczenie eq: ");i dalej nic nie pokazuje.
 


0 użytkowników i 1 Gość przegląda ten wątek.
0 użytkowników
Do góry