Prosba ke skripterům

Vše co přímo nesouvisí s hrou na Equilibrii

Moderátoři: Dungeon Servant, World Builder, Dungeon Master

Odpovědět
steel_martin
Příspěvky: 324
Registrován: 9. 3. 2006 11.03
Bydliště: Plzeň / Železná Ruda / Hobitín
Kontaktovat uživatele:

Prosba ke skripterům

Příspěvek od steel_martin »

Ahojte,

Dělám už několik let na vlastním modulu a momentálně dodělávám craft. Nejsem zkušený skripter a skripty jsou taky největší brzdou mého projektu, naštěstí jich už moc potřebovat nebudu. :o)

K věci:
Dám sem do code dva skripty - oba plní podobnou funkci, ovšem jeden je funkční a druhý nefunkční a to je taky důvod, proč si nevím rady, neboť netuším, kde je chyba.

Skript č. 1 - funkční
Pozice: OnClose, Placeable (kopie CEPového)
Funkce: Po zavření inventáře placeablu, zkontroluj, zda daný inventář obsahuje předmět a pokud ano, spusť danou konverzaci.

Kód: Vybrat vše

#include "nw_i0_tool"

object oPc = GetLastUsedBy();

int StartingConditional()
{


    if(!HasItem(GetObjectByTag("sm_zep_cook_map"), "sm_it_wheat"))
        return FALSE;

    ActionStartConversation(oPc, "sm_c_mortar");
        return TRUE;
}

Skript č.2 - Nefunkční
Pozice: OnClose, Placeable (kopie placeablu Neviditelný objekt)
Funkce: Po zavření inventáře placeablu, zkontroluj, zda daný inventář obsahuje tyto zmíněné předměty a pokud ano, spusť danou konverzaci.

Kód: Vybrat vše

#include "nw_i0_tool"

object oPc = GetLastUsedBy();

int StartingConditional()
{


    if(!HasItem(GetObjectByTag("sm_it_pec"), "sm_it_wheat"))
        return FALSE;

    if(!HasItem(GetObjectByTag("sm_it_pec"), "sm_cook_kvas"))
        return FALSE;

    if(!HasItem(GetObjectByTag("sm_it_pec"), "sm_cook_salt"))
        return FALSE;

    if(!HasItem(GetObjectByTag("sm_it_pec"), "DRINK_LOW_WATER"))
        return FALSE;


    ActionStartConversation(oPc, "sm_c_pec");
        return TRUE;
}


Pro tento skript jsem zkusil i alternativu, která také nefunguje:

Kód: Vybrat vše

void main()
{

object oPC = GetLastClosedBy();
object oPec = GetNearestObjectByTag("sm_it_pec");


if (!GetIsPC(oPC)) return;



if (GetItemPossessedBy(oPec, "sm_cook_flourwheat")== OBJECT_INVALID)
   return;

if (GetItemPossessedBy(oPec, "sm_cook_kvas")== OBJECT_INVALID)
   return;

if (GetItemPossessedBy(oPec, "sm_cook_salt")== OBJECT_INVALID)
   return;

if (GetItemPossessedBy(oPec, "drink_low_water")== OBJECT_INVALID)
   return;

ActionStartConversation(oPC, "sm_c_pec");

}
Ještě možná třeba zdůraznit, že druhý placeable je kopií placeablu Neviditelný objekt, který má přidaný inventář a je useable. Narozdíl od jiných placeablů, tento nedělá ono "cvak" při otevírání a zavířání inventáře :o)

Pokud by si někdo z vás udělal čas a třeba jen několika slovy napsal, v čem je chyba, byl bych mu moc zavázán.

Díky, steel
Game ID: Reverend_Malthas
labir
Příspěvky: 6702
Registrován: 18. 12. 2005 1.27
Bydliště: Sídlo u Amfiberai, sféra Equilibrie
Kontaktovat uživatele:

Příspěvek od labir »

No nevím, pokud to má dělat jen kontrolu obsahu na vypsané předměty podle tagu a pokud tam nějaký najde spustit rozhovor tak bych to napsal asi takhle pokud by to bylo spouštěné z rozhovoru jako podmínkový skript. Pokud je to spouštěné z události OnClosed tak nahraď int StartingConditional() za main() Píšu to popaměti bez kontroly tak tam možná budou chyby.

Kód: Vybrat vše

int StartingConditional() 
{
  object oSelf=OBJECT_SELF;
  object oPC=GetLastClosedBy();
  string sItems=GetLocalString(oSelf,"ITEMS_TAGS");
  string sDialog=GetLocalString(oSelf,"DIALOG");

  object oItem=GetFirstItemInInventory(oSelf);
  while (GetIsObjectValid(oItem))
    {
       if (FindSubString(sItems,"|"+GetTag(oItem)+"|")>=0)
         {
            ActionStartConversation(oPC,sDialog);
            return TRUE;
         } 
       oItem=GetNextItemInInventory(oSelf);
    }
  return FALSE;
}
Kde v tom placeablu nastastavíš proměnné DIALOG na ResRef dialogu co chceš se zapnout a promennou ITEMS_TAGS na seznam tagů detekovaných itemů oddělených a zapouzdřených znaky | tj. ve tvém příkladu by to bylo:

|sm_it_wheat|sm_cook_kvas|sm_cook_salt|DRINK_LOW_WATER|

Proč to zřejmě nefunguje - GetLastUsedBy nemusí korektně fungovat u některých speciálních placeablů pokud není použito z události OnUsed. Použití GetObjectByTag na nalezení sebe sama může vracet úplně jiný objekt jinde v modulu, lepší je použít meta proměnnou OBJECT_SELF. GetItemPossesedBy nemusí fungovat na placeablech.

Ta konstrukce !HasItem(GetObjectByTag("sm_it_pec"), "DRINK_LOW_WATER") je totiž dost zátěžová, HasItem není hardcoded funkce, ale normální psaná funkce která prochází celý inventář a kontroluje, takže když se ptáš na 4 itemy tak 4x prolezeš inventář po sobě, což je zbytečná zátěž, lepší se to prolézt jen jednou a při prvním výskytu skončit. Navíc opakování volání funkce GetObjectByTag není dobrý nápad, tohle je funkce, která docela žere systémové prostředky jak prohledává svět, takže pokud ji potřebuješ vícekrát volat se stejnými parametry tak si její výsledek ulož do proměnné. V některých případech je dobré její výsledek uložit i do globální proměnné modulu pokud se nebude měnit (např. vyhledání itemového bufferu atd..).
Když něco chcete, nevynucujte si to od okolí. Ptejte se, co vy sami pro to můžete udělat.
steel_martin
Příspěvky: 324
Registrován: 9. 3. 2006 11.03
Bydliště: Plzeň / Železná Ruda / Hobitín
Kontaktovat uživatele:

Příspěvek od steel_martin »

Ó děkuji labire za Tvojí podrobnou analýzu :)
labir píše: GetLastUsedBy nemusí korektně fungovat u některých speciálních placeablů pokud není použito z události OnUsed. Použití GetObjectByTag na nalezení sebe sama může vracet úplně jiný objekt jinde v modulu, lepší je použít meta proměnnou OBJECT_SELF. GetItemPossesedBy nemusí fungovat na placeablech.

Ta konstrukce !HasItem(GetObjectByTag("sm_it_pec"), "DRINK_LOW_WATER") je totiž dost zátěžová, HasItem není hardcoded funkce, ale normální psaná funkce která prochází celý inventář a kontroluje, takže když se ptáš na 4 itemy tak 4x prolezeš inventář po sobě, což je zbytečná zátěž, lepší se to prolézt jen jednou a při prvním výskytu skončit. Navíc opakování volání funkce GetObjectByTag není dobrý nápad, tohle je funkce, která docela žere systémové prostředky jak prohledává svět, takže pokud ji potřebuješ vícekrát volat se stejnými parametry tak si její výsledek ulož do proměnné. V některých případech je dobré její výsledek uložit i do globální proměnné modulu pokud se nebude měnit (např. vyhledání itemového bufferu atd..).
Budu si pamatovat - dík.
labir píše:… Pokud je to spouštěné z události OnClosed tak nahraď int StartingConditional() za main()
Při int StartingConditional() lze skript zkompilovat, ale při void main() nejde - jde pouze, pokud smažu všechny vraceče, tj. return TRUE; a return FALSE;
Bohužel ten skript nefunguje na OnClosed ani v režimu StartingConditional, tak ani při void main(). Všechny tagy jsem vyplnil.

Budu to zkoušet na jiném placeablu a zkusím to i přímo z rozhovoru za použití StartingConditional.

Pro informaci posílám Tvůj skript s mými tagy, jak je mam právě v modulu - posílam obě verze, jak s main() tak StartingConditional() - obojí jde zkompilovat, ale ve hře nefungují, tj. po zavření inventáře placeablu se nestane nic:


Kód: Vybrat vše

int StartingConditional()
{
  object oSelf=OBJECT_SELF;
  object oPC=GetLastClosedBy();
  string sItems=GetLocalString(oSelf,"|sm_cook_flourwheat|sm_cook_kvas|sm_cook_salt|DRINK_LOW_WATER|");
  string sDialog=GetLocalString(oSelf,"sm_c_pec");

  object oItem=GetFirstItemInInventory(oSelf);
  while (GetIsObjectValid(oItem))
    {
       if (FindSubString(sItems,"|"+GetTag(oItem)+"|")>=0)
         {
            ActionStartConversation(oPC,sDialog);
            return TRUE;
         }
       oItem=GetNextItemInInventory(oSelf);
    }
  return FALSE;
}

***********************************************************

void main()
{
  object oSelf=OBJECT_SELF;
  object oPC=GetLastClosedBy();
  string sItems=GetLocalString(oSelf,"|sm_cook_flourwheat|sm_cook_kvas|sm_cook_salt|DRINK_LOW_WATER|");
  string sDialog=GetLocalString(oSelf,"sm_c_pec");

  object oItem=GetFirstItemInInventory(oSelf);
  while (GetIsObjectValid(oItem))
    {
       if (FindSubString(sItems,"|"+GetTag(oItem)+"|")>=0)
         {
            ActionStartConversation(oPC,sDialog);
         }
       oItem=GetNextItemInInventory(oSelf);
    }
}
Game ID: Reverend_Malthas
labir
Příspěvky: 6702
Registrován: 18. 12. 2005 1.27
Bydliště: Sídlo u Amfiberai, sféra Equilibrie
Kontaktovat uživatele:

Příspěvek od labir »

steel_martin píše:...Pro informaci posílám Tvůj skript s mými tagy, jak je mam právě v modulu - posílam obě verze, jak s main() tak StartingConditional() - obojí jde zkompilovat, ale ve hře nefungují, tj. po zavření inventáře placeablu se nestane nic:


Kód: Vybrat vše

int StartingConditional()
{
  object oSelf=OBJECT_SELF;
  object oPC=GetLastClosedBy();
  string sItems=GetLocalString(oSelf,"|sm_cook_flourwheat|sm_cook_kvas|sm_cook_salt|DRINK_LOW_WATER|");
  string sDialog=GetLocalString(oSelf,"sm_c_pec");

  object oItem=GetFirstItemInInventory(oSelf);
  while (GetIsObjectValid(oItem))
    {
       if (FindSubString(sItems,"|"+GetTag(oItem)+"|")>=0)
         {
            ActionStartConversation(oPC,sDialog);
            return TRUE;
         }
       oItem=GetNextItemInInventory(oSelf);
    }
  return FALSE;
}

***********************************************************

void main()
{
  object oSelf=OBJECT_SELF;
  object oPC=GetLastClosedBy();
  string sItems=GetLocalString(oSelf,"|sm_cook_flourwheat|sm_cook_kvas|sm_cook_salt|DRINK_LOW_WATER|");
  string sDialog=GetLocalString(oSelf,"sm_c_pec");

  object oItem=GetFirstItemInInventory(oSelf);
  while (GetIsObjectValid(oItem))
    {
       if (FindSubString(sItems,"|"+GetTag(oItem)+"|")>=0)
         {
            ActionStartConversation(oPC,sDialog);
         }
       oItem=GetNextItemInInventory(oSelf);
    }
}
No popravdě tohle skutečně nic dělat nebude. Ty hodnoty ji tam dal špatně - neměl jsi je nahrazovat v kódu, ale dát je do toho placeablu pod jménem které jsi přepsal a s hodnotou kterou jsi tam napsal. Každý objekt v NWN (až na drobné výjimky) může v sobě držet proměnné - int/float/object/location/vector/string a tohle jsi měl udělat - založit v tom objektu placeablu na kterém to voláš proměnnou s daným jménem a hodnotou. Ten řádek, který jsi modifikoval dělá to, že tuto proměnnou s daným jménem přečte a vrací její hodnotu do proměnné skriptu. Jak jsi to zmodifikoval tak se snaží číst z objektu proměnnou s názvem |sm_cook_flourwheat|sm_cook_kvas|sm_cook_salt|DRINK_LOW_WATER|, kterou tam pochopitelně nenajde takže vrátí defaultní hodnotu "" - a proto skript nedělá nic.

Takhle se běžně píšou obecnější parametrické skripty. které jsou řízené parametry (proměnnými) uloženými v nějakých objektech (nejjednodušeji v objektu na kterém je skript spuštěn) takže ten samý skript můžeš použít jednou na kotlíku pro vaření polívky s jednou sadou proměnných a na kovadlině pro kování meče s jinou sadou proměnných.
Když něco chcete, nevynucujte si to od okolí. Ptejte se, co vy sami pro to můžete udělat.
steel_martin
Příspěvky: 324
Registrován: 9. 3. 2006 11.03
Bydliště: Plzeň / Železná Ruda / Hobitín
Kontaktovat uživatele:

Příspěvek od steel_martin »

Díky za odezvu. A jo, špatně sem to pochopil. Nyní už skript funguje, jak varianta se StartingConditional tak s void main (bez vracečů), akorát je problém, že rozhovor se spustí po vložení jakéhokoliv z předmětů, jejichž tagy jsou v proměnné BREAD_ING. Já bych potřeboval, aby se rozhovor spustil poze tehdy, pokud obsahuje všechny zmíněné předměty.

Kód: Vybrat vše

int StartingConditional()
{
  object oSelf=OBJECT_SELF;
  object oPC=GetLastClosedBy();
  string sItems=GetLocalString(oSelf,"BREAD_ING");
  string sDialog=GetLocalString(oSelf,"DIALOG");

  object oItem=GetFirstItemInInventory(oSelf);
  while (GetIsObjectValid(oItem))
    {
       if (FindSubString(sItems,"|"+GetTag(oItem)+"|")>=0)
         {
            ActionStartConversation(oPC,sDialog);
            return TRUE;
         }
       oItem=GetNextItemInInventory(oSelf);
    }
  return FALSE;
}
Díky :)

m
Game ID: Reverend_Malthas
Odpovědět