RPG Zone, Italian Forum & Community for role playing video games - ex Gothic Zone

[Tutorial] Npc e dialoghi, Lezione 5

« Older   Newer »
  Share  
view post Posted on 18/2/2015, 15:52     +1   +1   -1

Gothic Modder

Group:
Moderatore
Posts:
1,391
Rpg Point:
+83
Location:
L'Urbe!

Status:


Nella precedente lezione abbiamo introdotto le caratteristiche del linguaggio di scripting daedalus.

Ora passiamo al nostro primo atto di scripting pratico: la creazione di un npc e di un dialogo.

NOTA: per concludere con la creazione di un npc sarà necesessario utilizzare lo spacer. Alla fine di questa lezione coprirò MOLTO brevemente cosa vi serve sapere per ora. Per una trattazione più approfondita aspettare le lezioni successive.

Allora vediamo subito di iniziare con la creazione di un nuovo npc. Una volta che avete capito come si fa non solo potrete crearne di nuovi ma anche modificare quelli già esistenti. Bene, selezionate gothic come progetto attivo da gothic sourcer (se non l'avete già fatto, tasto destro -> set as active project), poi cliccate nuovament col destro sulla cartella npc -> new script file. PER ORA come nome metteteci quello che volete basta che lo fate finire con un .d. Vi comparirà poi una finestra che vi mostra tutti i file di gothic.dat dalla quale dovrete posizionare il vostro file. Dovete sapere infatti che i file non vengono compilati tutti contemporaneamente ma uno alla volta. Di conseguenza per poter utilizzare una determinata classe/funzione/variabile in un file questa deve essere già stata dichiarata nello stesso file o in un file PRECEDENTEMENTE compilato. Se ciò non avvenisse la compilazione terminerebbe con un errore. Voi quindi scorrete in basso e appena trovate le instanze degli npc (formate da trelettere_numeri_nomepersonaggio.d; non confondetevi con i dialoghi che iniziano con DIA!!), selezionatene una a caso e poi date ok. Questo dirà a gothic di compilare il vostro file dopo il file selezionato. Se spuntate invece il riquadro "insert before cursor", questo verrà compilato prima. Selezionatene uno a caso o in ordine alfabetico, come volete, e date ok. Ecco a voi il vostro primo file aggiunto a gothic.dat :D

Adesso vi ritroverete con un file vuoto. Ora, serve "riempirlo". Tenete aperto un qualsiasi altro file di un NPC come esempio e seguitemi:

CODICE
instance KDF_500_Pyrokar(Npc_Default)
{
       name[0] = "Pyrokar";
       guild = GIL_KDF;
       id = 500;
       voice = 11;
       flags = NPC_FLAG_IMMORTAL;
       npcType = npctype_main;
       B_SetAttributesToChapter(self,6);
       fight_tactic = FAI_HUMAN_STRONG;
       B_SetNpcVisual(self,MALE,"Hum_Head_Bald",Face_N_ImportantOld,BodyTex_N,ItAr_KDF_H);
       Mdl_SetModelFatness(self,1);
       Mdl_ApplyOverlayMds(self,"Humans_Mage.mds");
       B_GiveNpcTalents(self);
       B_SetFightSkills(self,30);
       daily_routine = Rtn_Start_500;
};


func void Rtn_Start_500()
{
       TA_Sit_Throne(8,0,23,0,"NW_MONASTERY_THRONE_01");
       TA_Sit_Throne(23,0,8,0,"NW_MONASTERY_THRONE_01");
};

func void Rtn_RitualInnosEyeRepair_500()
{
       TA_Stand_Guarding(8,0,23,0,"NW_TROLLAREA_RITUAL_02");
       TA_Stand_Guarding(23,0,8,0,"NW_TROLLAREA_RITUAL_02");
};

func void Rtn_RitualInnosEye_500()
{
       TA_Circle(8,0,23,0,"NW_TROLLAREA_RITUAL_02");
       TA_Circle(23,0,8,0,"NW_TROLLAREA_RITUAL_02");
};


Questa è la classe del buon vecchio pyrokar. Vediamo cosa significa riga per riga ciò che c'è scritto:

La prima riga contiene la definizione dell'istanza pyrokar, quindi il nome dell'istanza, e la classe madre (in questo caso il prototipo Npc_Default).
Dalla prima del blocco tra parentesi graffe inizia l'assegnazione di valori alle proprietà della classe.

Se andate a vedere di nuovo la classe originale C_NPC vedrete che name non è semplicemente una stringa ma un array di stringhe, quindi, in altre parole, una lista di stringhe, in questo caso di lunghezza 5. Non è chiaro il perché di ciò (noterete che non tutto quello che hanno fatto i Piranha Bytes ha senso), tuttavia a noi servirà soltanto la prima voce di questo array cioè name[0]. Il valore (tra virgolette per indicare una stringa), sarà il nome che comparirà sopra il personaggio e sopra i dialoghi.

guild invece è un intero. Nella classe constants.d ad ogni gilda è associato un numero. Non tratteremo per ora della creazione di nuove gilde, quindi dovete sceglierne una tra quelle già esistenti (milizia, paladini, mercenari, cacciatori di draghi, contadini, novizi, maghi, pirati, maghi dell'acqua, banditi). Andate a cercare in constants.d quella che vi serve. Se non appartiene a nessuna di queste c'è anche la possibilità di non attribuirne nessuna: GIL_NONE.

id corrisponde all'identificativo del npc. Deve essere UNIVOCO!! Gli unici a non avercelo unico nel gioco originale sono i personaggi di test (storyhelper, charachterhelper, ecc..) e l'eroe che hanno zero. Io però ho assegnato zero solo all'eroe e ai primi 9999, proprio per rimarcare l'univocità ed evitare errori. Ogni gilda ha un id identificativo che aumenta gradualmente. Osservate bene le altre istanze della gilda relativa al vostro personaggio, e scegliete di conseguenza un numero maggiore.

Ora possiamo quindi dare un nome decente alla nostra classe. Le classi degli npc sono infatti date da: GILDA_ID_NOME. E così dovrete rinominare anche il vostro file. Cliccateci col destro nel menu a sinistra -> rename e dategli lo stesso nome terminato da .d.

Bene, vediamo il resto. voice indica la voce che avrà il personaggio, NON durante i dialoghi. Cioè quando impreca, e parla con altri di sottofondo. Cercate un personaggio simile al vostro e dategli lo stesso numero. Non date il numero 15 che è univoco dell'eroe!!

flags nella maggior parte dei casi qui ci sarà zero. Ma capita che così non è. Ci sono tre possibili flag definite sempre in constants.d: npc_flag_immortal, _friend, _ghost. Diciamo che le diciture sono abbastanza chiare, il primo lo rende immortale e viene usato per i personaggi senza i quali non riusciresti a finire il gioco, il secondo viene usato per gli amici (quindi lares, lee, diego, ecc..), il terzo per i fantasmi. Potete anche utilizzarli insieme. Come? Non con un +, ma con il simbolo di unione, per esempio NPC_FLAG_IMMORTAL | NPC_FLAG_FRIEND.

npcType indica il tipo di npc. Fondamentalmente si dividono in tre tipi: main, ambient e friend. Main sono tutti queli con i nomi, quelli che hanno dialoghi propri, ambient sono tutit quelli senza nome che hanno dialoghi "generici", per friend vale lo stesso discorso di flags. Cercate npctype in ai_constants (dentro la cartella ai_intern) e vedete tutti i vari tipi. I numeri dal 3 al 7 indicano semplicemente che: ocmain/ambient sta a campo vecchio, bl_main/ambient, sta DENTRO il campo dei banditi, bl_ambient sta FUORI il campo dei banditi. Siccome penso che voi vogliate inserire personaggi principali alla fine quelli che più userete è npctype_main nel relativo ambiente.

B_SetAttributesToChapter è una funzione che serve ad assegnare valori standard agli attributi dei personaggi. self indica che verranno assegnati all'istanza in cui è chiamata la funzione, e 6 indica che gli verranno assegnati i valori più alti. La funzione la troverete in npc_scripts se volete studiarla/modificarla.

fight_tactic indica che tipo di tattica di combattimento usa. Per gli umani ci sono coward, normal, strong e master.

B_SetNpcVisual crea la visuale del personaggio. I parametri sono self (questo personaggio), il sesso (male, female), la mesh della testa (vedere dentro anims.vdf per i nomi o cercare dentro altre instanze per quello che vi serve) come stringa, la texture della testa (dentro ai_constants vi sono tutte le possibilità, che potete anche vedere da goman aprendo il file textures.vdf), la texture del corpo (lasciate quella standard visto che porterà comunque un vestito o un'armatura), l'ultima è l'instanza dell'armatura che potete vedere in it_Armor o in it_addon_armor).

Mdl_SetModelFatness indica la "stazza" del personaggio. Potete dargli un valore tra -6 e 6 a seconda di quanto lo volete scheletrico od obeso :D

Mdl_ApplyOverlayMds applica un overlay, cioè delle animazioni particolari che si sovrapporanno a quelle di base. Cercate dentro la cartella _work/data/anims/mds_overlay per tutte le possibilità.

B_GiveNpcTalents è una funzione standard che da semplicemente tutti i talenti tranne le acrobazie.

B_SetFightSkills imposta le abilità di combattimento al valore dato come parametro in percentuale. La funzione la trovate sempre in npc_script.

Arriviamo all'ultima, daily_routine. Indica appunto la routine giornaliera. Quella che chiamerete qui sarà quella di partenza, e la potete vedere sotto. Poi queste potranno essere cambiate tramite script. Il nome delle routine DEVE essere Rtn_Nomeroutine_IDpersonaggio. Nelle istruzioni a seguire dovrete impostare che tipo di routine sarà, chiamando la funzione corretta. Le routine le potete trovare in AI -> Human -> TA. I quattro parametri sono: ora inizio, minuto inizio, ora fine, minuto fine. Per indicare che farà tutto il giorno la stessa cosa dovrete inserirla due volte. La prima con l'orario che volete voi, la seconda con lo stesso orario con inizio e fine scambiati. Per esempio dalle 8 alle 22, e dalle 22 alle 8. Così create un ciclo infinito. Il quinto parametro indica il waypoint in cui eseguirete l'azione. A fine lezione una piccola appendice per trovare quello che vi serve.


Bene ora avete il vostro personaggio. Ma non lo troverete nel mondo, perché dovete ancora inserirlo. Aprite npc_globals e create un altra variabile di tipo c_npc col nome del vostro personaggio. Nella funzione B_InitNpcGlobals sotto, create infine la variabile del personaggio così: nomevariabile = Hlp_GetNpc(nomeinstanza). Prendete come modello gli altri!
Infine aprite il file startup. Lì troverete diverse funzioni che rappresentano diverse zone dei mondi. Non posso dirvi dove dovrete metterlo, dovrete capirlo dal nome. newworld significa khorinis, oldworld valle delle miniere, addonworld jharkendar e dragonisland irdorath. Poi ci sono delle sottozone in inglese ma potete benissimo capire più o meno a che zone corrispondono se ci avete mai giocato a gothic :D. Se avete dubbi su questo scrivete pure qui sotto :). Comunque una volta trovata la zona prendete come modello gli altri spawn e chiamate la funzione Wld_InsertNpc(NPC,"WAYPOINT"). Al posto di npc usate la variabile dichiarata in npc_globals e al posto di waypoint, o il waypoint della routine iniziale o uno di quelli standard (li troverete guardando gli altri npc in zona).
Bene ora avete il vostro npc nel gioco :D



Questo però sarà un npc piuttosto piatto poverino. Infatti non vi rivolgerà mai la parola. Creiamo quindi un piccolo dialogo anche per lui.
Create un nuovo file di dialogo in story -> dialoge e come nome DIA_nomeinstanza.d. Come al solito anche questo posizionatelo insieme agli altri dialoghi.

E prendiamo un esempio di dialogo (guarda caso pyrokar :D):

CODICE
instance DIA_Pyrokar_Hagen(C_Info)
{
       npc = KDF_500_Pyrokar;
       nr = 10;
       condition = DIA_Pyrokar_Hagen_Condition;
       information = DIA_Pyrokar_Hagen_Info;
       important = FALSE;
       permanent = FALSE;
       description = "Devo parlare con i paladini. È urgente.";
};


func int DIA_Pyrokar_Hagen_Condition()
{
       if(other.guild == GIL_NOV)
       {
               return TRUE;
       };
};

func void DIA_Pyrokar_Hagen_Info()
{
       AI_Output(other,self,"DIA_Pyrokar_Hagen_15_00");        //Devo parlare con i paladini. È una questione urgente.
       AI_Output(self,other,"DIA_Pyrokar_Hagen_11_01");        //Vuoi dirci come mai vuoi parlare con loro?
       AI_Output(other,self,"DIA_Pyrokar_Hagen_15_02");        //Ho un messaggio urgente da riferirgli.
       AI_Output(self,other,"DIA_Pyrokar_Hagen_11_03");        //E sarebbe?
       AI_Output(other,self,"DIA_Pyrokar_Hagen_15_04");        //Un esercito del male guidato dai draghi si sta radunando nella Valle delle Miniere! Dobbiamo fermarli prima che sia troppo tardi.
       AI_Output(self,other,"DIA_Pyrokar_Hagen_11_05");        //Mmmh. Dovremo valutare le tue parole, novizio. Quando sarà il momento, ti faremo sapere cos'ha deciso il nostro consiglio.
       AI_Output(self,other,"DIA_Pyrokar_Hagen_11_06");        //Nel frattempo faresti meglio a tornare ai tuoi compiti da novizio.
       if(Npc_KnowsInfo(other,DIA_Pyrokar_Auge))
       {
               AI_Output(self,other,"DIA_Pyrokar_ALL_11_07");        //Bene, non vogliamo trattenerti ulteriormente dal fare il tuo lavoro. Ora puoi andare.
               AI_StopProcessInfos(self);
       };
};


La prima è la vera e propria instanza di dialogo. Come vedete eredita infatti da C_INFO. La struttura del nome è DIA_NomePersonaggio_DescrizioneDialogo. Vediamo ora le sue proprietà:

npc indica ovviamente a quale personaggio appartiene il dialogo.

nr è un numero che indica la priorità del dialogo. Numeri più alti posizionano la scelta del dialogo più in alto. Non è assolutamente univoco, quindi ce ne possono essere più d'uno contemporaneamente con lo stesso numero, solo che in quel caso lasciate a gothic l'ordine ;)

condition indica la funzione che determina se il dialogo avverrà o meno

information indica la funzione contenente le stringhe di dialogo

permanent se vero (TRUE) indica che fintanto che ci sono le condizioni il dialogo potrà essere ripetuto

important se vero il dialogo viene iniziato dal npc e non dall'eroe

description indica la stringa che comparirà nelle opzioni di dialogo, da omettere se important è impostato su TRUE


Bene ora passiamo alla condizione di dialogo. È un funzione int cioè ritorna un intero. In daedalus infatti i valori booleani di vero e falso sono rappresentati da interi, 0 è falso, tutti gli altri numeri è vero. In questa funzione sarà presente una condizione if in cui starà a voi impostare la condizione necessaria. Questa è determinata in genere da variabili o stato di missione. Osservate altri dialoghi per capire meglio. Qui non avviene ma in realtà è buona norma fare in modo che la funzione ritorni sempre un valore. Qui per esempio ritorna vero se la gilda dell'eroe è quella dei novizi, ma non ritorna niente se non lo è. In questo caso sarebbe opportuno un ramo else che ritorna falso.

ATTENZIONE: state bene attenti alle condizioni! In quanto tantissimi bug nelle missioni derivano appunto da condizioni male impostate! Inoltre se impostate male le condizioni e nell'istanza di dialogo assegnate sia a important sia a permenent il valore vero, andrete incontro ad un dialogo infinito!!!


Infine arriviamo alla funzione di dialogo. Questa non dovrà ritornare alcun valore, quindi sarà di tipo void. La funzione che dovete chiamare per i dialoghi è AI_Output(PARLANTE,RICEVENTE,"NOMEDIALOGO"). Senza scomodarci ad utilizzare le instanze precise ce ne sono due che fanno al caso nostro: self e other. Sono due instanze variabili, che cambiano a seconda della situazione. Nei dialoghi self corrisponde al npc e other all'eroe. Quindi con AI_Output(self,other,..) parla l'npc viceversa l'eroe. Il nome del dialogo indica il file audio del doppiaggio. Anche se non ce lo avete però è buona norma inserirlo. La struttura è "Nomeistanzadialogo_voceparlante_numerocrescente". Cioè in questo caso il nome del dialogo è DIA_Pyrokar_Hagen, la voce di pyrokar è 11, quella dell'eroe è 15 e quindi a seconda di chi parla si mette l'uno o l'altro. L'ultimo è un numero crescente. Come si fa fa a mettere le stringhe di dialogo quindi? Beh, vedete quei commenti accanto? I commenti (a linea singola!!) accanto ad AI_Output sono gli unici che non vengono ignorati e vengono registrati nel file ou.bin!.
AI_StopProcessInfos(self) indica infine la fine del dialogo.


Bene spero di essere stato chiaro. Qui la questione non è difficile ma si tratta solo di tanta pratica per prendere domestichezza con le condizioni di dialogo e le proprietà degli npc.

Nella prossima lezione parlerò invece di mostri e oggetti.

Ciao :camberman.gif: :camberman.gif:

Torna all'indice delle lezioni



Edited by Frank-95 - 23/2/2015, 19:48
 
Top
view post Posted on 18/2/2015, 17:41     +1   -1
Avatar

Advanced Member

Group:
Rpg Veteran
Posts:
1,300
Rpg Point:
+58
Location:
Khorinis, Quartieri alti

Status:


Ti sei dimenticato di commentare la condizione:
CITAZIONE
if(Npc_KnowsInfo(other,DIA_Pyrokar_Auge))

Comunque ora mancano solo i compiti per casa =D... a parte gli scherzi tu e diablo avete deciso come fare o meglio dire se farli i video tutorial?? Perchè leggere un tutorial ma vedere con propri occhi e tutto un'altro mondo.

Comunque per semplificare le cose c'è un tool chiamato NPC Maker ma è in polacco però in certi versi è comprensibile, ti da addirittura l'anteprima dello script. Ma ora non ricordo se è compatibile con gli script di gothic 2 o solo del primo.

Ok, ho trovato un altro tools in inglese però ed è molto carino, vi da anche l'anteprima degli item e dell'aspetto che date all'NPC che state creando. Eccovi il link. Cliccate sul primo link (link to English Version)
 
Top
view post Posted on 18/2/2015, 18:39     +1   -1

Gothic Modder

Group:
Moderatore
Posts:
1,391
Rpg Point:
+83
Location:
L'Urbe!

Status:


Mah io ho sempre preferito fare a mano :P Comunque metterò anche il link.

Per quanto riguarda la funzione penso farò un appendice alla fine per spiegare tutte le funzioni di gioco. Così faccio un po' d'ordine.
 
Top
view post Posted on 19/2/2015, 14:55     +1   -1

Gothic Modder

Group:
Moderatore
Posts:
1,391
Rpg Point:
+83
Location:
L'Urbe!

Status:


Ho cambiato un po' la formattazione perchè si capiva poco :P
 
Top
view post Posted on 31/1/2017, 18:44     +1   -1
Avatar

Advanced Member

Group:
Rpg Veteran
Posts:
1,300
Rpg Point:
+58
Location:
Khorinis, Quartieri alti

Status:


Frank, sto cercando di far interagire l'eroe con la mola ma, pur inserendo il nome del file creato nella sezione onStateFunc dallo spacer, non compare nessun dialogo. La cosa incredibile è che il dialogo parte se vado a letto :blink: . Come cavolo faccio a farlo interagire? Sto su gothic 1
 
Top
view post Posted on 31/1/2017, 20:57     +1   -1

Gothic Modder

Group:
Moderatore
Posts:
1,391
Rpg Point:
+83
Location:
L'Urbe!

Status:


Oddio su gothic 1 non so se sia diverso.

Comunque dallo spacer assicurati di aver scritto la funzione in maiuscolo nel dubbio. E negli script di gothic il nome della fnzione in maiuscolo seguito da _S1

Tipo: onStateFunc: MYFUNC (dallo spacer), e in gothic func void MYFUNC_S1()
 
Top
view post Posted on 31/1/2017, 21:20     +1   -1
Avatar

Advanced Member

Group:
Rpg Veteran
Posts:
1,300
Rpg Point:
+58
Location:
Khorinis, Quartieri alti

Status:


Io ho creato questo script basandomi su quello che viene usato per dormire (sleepabit):

CITAZIONE
instance PC_NoSharp(C_Info)
{
npc = PC_Hero;
nr = 999;
condition = PC_NoSharping_Condition;
information = PC_NoSharping_Info;
important = 0;
permanent = 1;
description = DIALOG_ENDE;
};


func int PC_NoSharping_Condition()
{
return 1;
};

func void PC_NoSharping_Info()
{
AI_StopProcessInfos(self);
};


instance PC_Sharping_1h_sword_01(C_Info)
{
npc = PC_Hero;
condition = PC_Sharping_1h_sword_01_condition;
information = PC_Sharping_1h_sword_01_info;
important = 0;
permanent = 0;
description = "Affila spada grezza (+5 danno)";
};


func int PC_Sharping_1h_sword_01_condition()
{
if(Npc_HasItems(hero,ItMw_1H_Sword_01)>= 1 )
{
return 1;
};
return 0;
};

func void PC_Sharping_1h_sword_01_info()
{
Npc_RemoveInvItem(hero, ItMw_1H_Sword_01);
CreateInvItem(hero, ItMw_1H_Sword_01_sharp);
AI_StopProcessInfos(self);
};

Effettivamente non ho inserito la funzione con s1 :D che sarebbe questa nello script sleepabit:

CITAZIONE
func void sleepabit_s1()
{
var C_Npc her;
var C_Npc rock;
her = Hlp_GetNpc(PC_Hero);
rock = Hlp_GetNpc(PC_Rockefeller);
if((Hlp_GetInstanceID(self) == Hlp_GetInstanceID(her)) || (Hlp_GetInstanceID(self) == Hlp_GetInstanceID(rock)))
{
self.aivar[AIV_INVINCIBLE] = TRUE;
AI_ProcessInfos(her);
};
};

A cosa serve questa funzione e cosa dovrebbe fare? molti comandi ancora devo capire a che servono =\
 
Top
view post Posted on 31/1/2017, 21:46     +1   -1
Avatar

Advanced Member

Group:
Rpg Veteran
Posts:
1,300
Rpg Point:
+58
Location:
Khorinis, Quartieri alti

Status:


Aggiustato lo script e ora parte il dialogo, l'unico problema è che sia se interagisco con il letto e sia se interagisco con la mola escono le stesse opzioni. Ho comparato le funzioni S1 di G1 e G2 e vedo che in G2 viene specificato il genere di iterazione, cioè se stai "dialogando" per dormire, per forgiare, ecc. Ora non so come potrei fare a estrapolare con che mob sto interagendo =\.

EDIT:

Risolto tutto (piu o meno). Ora funziona tutto quasi perfettamente. Ho risolto creando una variabile globale inizializzata a 0 e, ad ogni numero, associo un mobsi (penso che si chiamano così :D). Lo so, è una soluzione molto grezza, ma questa è l'unica che ho trovato con le mie conoscenze attuali

Non riesco a risolvere una cosa. Praticamente, di default, la mola utilizza una lama per creare automaticamente una spada grezza. Ora il problema è che non riesco a trovare lo script che mi genera questa maledetta spada! Precisamente me la crea quando mi allontano dall'incudine (dopo aver finito il dialogo bisogna premere S per allontanarsi altrimenti rimane in loop l'animazione dell'affilatura). Sai se c'è una funzione che mi faccia allontanare dalla mola automaticamente?

Edited by Mr.Slash - 1/2/2017, 00:22
 
Top
view post Posted on 1/2/2017, 11:14     +1   -1

Gothic Modder

Group:
Moderatore
Posts:
1,391
Rpg Point:
+83
Location:
L'Urbe!

Status:


Ma non è che semplicemente non lo inizializzavi bene?
In gothic 2 hai questo:

CODICE
func void SharpSword_S1()
{
       var C_Npc her;
       her = Hlp_GetNpc(PC_Hero);
       if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(her)) //controlla se è il giocatore che sta usando l'oggetto
       {
               SwordToSharp = Npc_GetEquippedMeleeWeapon(hero);
               self.aivar[AIV_INVINCIBLE] = TRUE; // evita eventuali bug se ti attaccano
               PLAYER_MOBSI_PRODUCTION = MOBSI_SharpSword; //imposta il mob utilizzato (usato da tutti i mob)
               AI_ProcessInfos(her); //iniza il dialogo
       };
};


CODICE
instance PC_SharpSword_End(C_Info)
{
       npc = PC_Hero;
       nr = 999;
       condition = PC_SharpSword_End_Condition;
       information = PC_SharpSword_End_Info;
       permanent = TRUE;
       description = Dialog_Ende;
};


func int PC_SharpSword_End_Condition()
{
       if(PLAYER_MOBSI_PRODUCTION == MOBSI_SharpSword) //presente solo se effetivamente si sta usando la mola
       {
               return TRUE;
       };
};

func void PC_SharpSword_End_Info()
{
       b_endproductiondialog();
};

func void b_endproductiondialog()
{
       AI_StopProcessInfos(self);
       Wld_StopEffect("DEMENTOR_FX"); //per fermare gli eventuali effetti visivi dei cercatori
       self.aivar[AIV_INVINCIBLE] = FALSE;
       SwordToSharp = MEM_NullToInst();
       PLAYER_MOBSI_PRODUCTION = MOBSI_NONE;
};


E in AI_Constants questo:

CODICE
const int         MOBSI_NONE                                        = 0;
const int        MOBSI_SmithWeapon                        = 1;
const int        MOBSI_SleepAbit                                = 2;
const int        MOBSI_MakeRune                                = 3;
const int        MOBSI_PotionAlchemy                        = 4;
const int        MOBSI_PRAYSHRINE                        = 5;        
const int        MOBSI_GOLDHACKEN                        = 6;
const int        MOBSI_PRAYIDOL                                = 7;
const int        MOBSI_SharpSword                        = 8;
const int        MOBSI_CookPan                                = 9;
const int        MOBSI_Board                                        = 10;
const int        MOBSI_CutWood                                = 11;
const int        MOBSI_MakeArrows                        = 12;
const int        MOBSI_WorkWood                                = 13;

var int         PLAYER_MOBSI_PRODUCTION;


Quindi si è necessaria una variabile globale come hai fatto te, ma vedi se c'è già una lista di variabili per altri mob.

Poi in che senso usa una lama per creare una lama grezza? La mola non è la pietra per affilare? In che senso crea?
Comunque in tutti i casi, i mob sono gestiti dal motore. Quindi o giochi con il motore o non puoi farci nulla... Non sta in gothic.dat
 
Top
view post Posted on 19/2/2017, 12:32     +1   -1
Avatar

Advanced Member

Group:
Rpg Veteran
Posts:
1,300
Rpg Point:
+58
Location:
Khorinis, Quartieri alti

Status:


Frank, ma c'è bisogno di impostare il nome del freepoint in un certo modo? Perche in gothic 1 ho messo il WP e vicino il FP ma l'NPC che ho aggiunto rimane fermo lì senza fare niente anche se gli dico di raccogliere il riso ad un certo orario
 
Top
view post Posted on 19/2/2017, 16:37     +1   -1

Gothic Modder

Group:
Moderatore
Posts:
1,391
Rpg Point:
+83
Location:
L'Urbe!

Status:


Dipende, in alcuni casi si, è necessario che ci sia una certa stringa.

Apri il file ZS_tuaroutine e vedi se c'è qualche chiamata a funzioni relative ai freepoints (FP) come Wld_IsFPAvailable(self,"XXX"), AI_GotoFP(self,"XXX") o Npc_IsOnFP(self,"XXX").

In quel caso rinomina il freepoints lì vicino come FP_XXX_QUELLOCHETIPARE
 
Top
view post Posted on 19/2/2017, 16:57     +1   -1
Avatar

Advanced Member

Group:
Rpg Veteran
Posts:
1,300
Rpg Point:
+58
Location:
Khorinis, Quartieri alti

Status:


ok, provo e ti faccio sapere

edit: ho preso come esempio zs_guard.d

CITAZIONE
func void ZS_Guard()
{
PrintDebugNpc(PD_TA_FRAME,"ZS_Guard");
GuardPerception();
Npc_PercEnable(self,PERC_ASSESSPLAYER,B_AssessSC);
AI_Standup(self);
AI_SetWalkMode(self,NPC_WALK);
AI_GotoWP(self,self.wp);
B_InitArmor();
};

func void ZS_Guard_Loop()
{
PrintDebugNpc(PD_TA_LOOP,"ZS_Guard_Loop");
B_GotoFP(self,"GUARD");
if(Npc_GetDistToNpc(self,hero) < 800)
{
B_SmartTurnToNpc(self,hero);
}
else
{
AI_AlignToFP(self);
};
B_PlayArmor();
AI_Wait(self,0.5);
};

func void ZS_Guard_End()
{
PrintDebugNpc(PD_TA_FRAME,"ZS_Guard_End");
B_ExitArmor();
};

Quindi, se ho ben capito dovrebbe stare un FP che inizia come "FP_GUARD_XXX". Giusto?
 
Top
view post Posted on 19/2/2017, 17:15     +1   -1
Avatar

Advanced Member

Group:
Rpg Veteran
Posts:
1,300
Rpg Point:
+58
Location:
Khorinis, Quartieri alti

Status:


Ho modificato il nome del FP in "FP_GUARD_CONSTANTIN_01" e non funziona lo stesso...rimane in piedi e basta. Non è che casomai devo rinominare anche il WP in un modo preciso? Bisogna collegare il WP con il FP (se si puo fare o se centra qualcosa)?
 
Top
view post Posted on 23/2/2017, 14:08     +1   -1

Gothic Modder

Group:
Moderatore
Posts:
1,391
Rpg Point:
+83
Location:
L'Urbe!

Status:


No i WP e FP non possono essere collegati... Eventualmente prova a rinominare anche i WP, ma non penso sia quello il problema. Hai per caso aggiunto WP nuovi?
 
Top
view post Posted on 23/2/2017, 14:44     +1   -1
Avatar

Advanced Member

Group:
Rpg Veteran
Posts:
1,300
Rpg Point:
+58
Location:
Khorinis, Quartieri alti

Status:


Si...ho visto che raccogliere il riso e sedersi sulla panca funzionano, ma rimanere di guardia (TA_Guard) non funziona, rimane li fermo e basta. Va anche a dormire, ma il problema è che si sdraia e dopo qualche secondo si rialza e poi si rimette a letto per poi rialzarsi, e così via
 
Top
27 replies since 18/2/2015, 15:52   708 views
  Share