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 24/3/2017, 18:04     +1   -1
Avatar

Advanced Member

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

Status:


Frank (scusa se rompo di tanto in tanto :D), vorrei implementare un nuovo mob (la bacheca) solo che non so come fare a far interagire l'eroe correttamente con essa. Praticamente ho preso il file asc della sedia e, al posto di essa, ho messo la bacheca. Esporto il tutto in formato asc, creo lo script per il dialogo (quello che la funzione principale deve avere _S1 alla fine), aggiungo il mob nello spacer (ocMobInter) e aggiungo anche il nome della funzione nella voce onStateFunc però, quando interagisco, l'eroe rimane in piedi orizzontalmente e posso anche controllarlo, ma non compare proprio il dialogo. Cosa dovrei fare precisamente?

Edit:
Frank, come si chiama il programma che permette di decompilare gli script compilati con ikarus al suo interno? Purtroppo si sono corrotti alcuni script e quindi mi tocca decompilare quelli compilati

Edited by Mr.Slash - 28/3/2017, 21:46
 
Top
view post Posted on 29/3/2017, 18:45     +1   -1
Avatar

Advanced Member

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

Status:


Un'altra cosa...vorrei poter parlare con un mostro (lupo) e quindi ho creato un una nuova istanza basandomi su quella di default:

CITAZIONE
prototype Mst_Default_Wolf(C_Npc)
{
name[0] = "Lupo";
guild = GIL_WOLF;
aivar[AIV_IMPORTANT] = ID_WOLF;
level = 9;
attribute[ATR_STRENGTH] = 40;
attribute[ATR_DEXTERITY] = 40;
attribute[ATR_HITPOINTS_MAX] = 80;
attribute[ATR_HITPOINTS] = 80;
attribute[ATR_MANA_MAX] = 0;
attribute[ATR_MANA] = 0;
protection[PROT_BLUNT] = 20;
protection[PROT_EDGE] = 20;
protection[PROT_POINT] = 10;
protection[PROT_FIRE] = 10;
protection[PROT_FLY] = 0;
protection[PROT_MAGIC] = 0;
damagetype = DAM_EDGE;
fight_tactic = FAI_WOLF;
senses = SENSE_HEAR | SENSE_SEE | SENSE_SMELL;
senses_range = 3000;
aivar[AIV_FINDABLE] = PACKHUNTER;
aivar[AIV_PCISSTRONGER] = 1500;
aivar[AIV_BEENATTACKED] = 1200;
aivar[AIV_HIGHWAYMEN] = 500;
aivar[AIV_HAS_ERPRESSED] = 3;
aivar[AIV_BEGGAR] = 10;
aivar[AIV_OBSERVEINTRUDER] = TRUE;
start_aistate = ZS_MM_AllScheduler;
aivar[AIV_Trigger3] = OnlyRoutine;
};

func void Set_Wolf_Visuals()
{
Mdl_SetVisual(self,"Wolf.mds");
Mdl_SetVisualBody(self,"Wol_Body",DEFAULT,DEFAULT,"",DEFAULT,DEFAULT,-1);
};

instance PcHeroFriend_Wolf(Mst_Default_Wolf)
{
Set_Wolf_Visuals();
Npc_SetToFistMode(self);
name[0] = "Lupo addomesticato";
senses_range = 1;
guild = GIL_PET;
start_aistate = ZS_MM_SummonedByPC;
aivar[AIV_ISLOOKING] = 1;
aivar[AIV_MOVINGMOB] = TRUE;
};

...ho anche creato uno script di dialogo per porvare, ma non succede niente, neanche si gira verso di me:

CITAZIONE
instance DIA_WolfHeroFriend_EXIT(C_Info)
{
npc = PcHeroFriend_Wolf;
nr = 999;
condition = DIA_WolfHeroFriend_EXIT_Condition;
information = DIA_WolfHeroFriend_EXIT_Info;
permanent = 1;
description = DIALOG_ENDE;
};


func int DIA_WolfHeroFriend_EXIT_Condition()
{
return 1;
};

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

instance DIA_WolfHeroFriend_Hello(C_Info)
{
npc = PcHeroFriend_Wolf;
nr = 1;
condition = DIA_WolfHeroFriend_Hello_Condition;
information = DIA_WolfHeroFriend_Hello_Info;
permanent = 1;
description = "Ciao";
};

func int DIA_WolfHeroFriend_Hello_Condition()
{
return 1;
};

func void DIA_WolfHeroFriend_Hello_Info()
{
AI_Output(other,self,"DIA_WolfHeroFriend_Hello_15_00"); //Ciao bello.
AI_Output(other,self,"DIA_WolfHeroFriend_Hello_15_00"); //(annuisce) *wolf* *wolf*.
};

Come posso risolvere?
 
Top
view post Posted on 31/3/2017, 14:22     +1   -1

Gothic Modder

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

Status:


Allora per quanto riguarda la bacheca io ho fatto così:

Ti crei la mesh che deve contenere la mesh di un npc dal lato in cui dovrai utilizzarla (vedi per esempio la sedia), ed esportala come asc con il nome "xxx_01.asc" (xxx nome che vuoi). Gli scrivi poi la onStateFunc in maiuscolo per sicurezza, tipo "FUNC"

Poi devi modificare anche le animazioni di humans. Quindi decompila humans.msb, o mds non mi ricordo che estensione ha gothic1, apri il file mds decompilato e aggiungi queste stringhe:

CODICE
ani                        ("t_Board_Stand_2_S0"                        1        "s_Board_S0"        0.1        0.0        M.        "Hum_Guard_Ambient_B_Jue01.asc"                F        1        1)
                       ani                        ("s_Board_S0"                                1        "s_Board_S0"        0.0        0.0        M.        "Hum_Guard_Ambient_B_Jue01.asc"                F        1        1)
                       ani                        ("t_Board_S0_2_Stand"                        1        ""                0.1        0.1        M.        "Hum_Guard_Ambient_B_Jue01.asc"                R        1        1)
                       ani                        ("t_Board_S0_2_S1"                        1        "s_Board_S1"        0.0        0.0        M.        "Hum_Guard_Ambient_B_Jue01.asc"                F        1        24        FPS:10)
                       ani                        ("t_Board_S1_2_S0"                        1        "s_Board_S0"        0.1        0.1        M.        "Hum_Guard_Ambient_B_Jue01.asc"                F        75        85        FPS:10)
                       ani                        ("s_Board_S1"                                1        "s_Board_S1"        0.0        0.0        M.        "Hum_Guard_Ambient_B_Jue01.asc"                F        25        74        FPS:5)


Dove invece di board ci metti il nome func della funzione e ovviamente poi l'animazione la regoli di conseguenza. Io ho usato Hum_Guard_Ambient_B_Jue01.asc che è quella delle guardie quando si mettono a braccia conserte. I numeri dopo F sono i frame iniziali e finali (ed eventualmente la velocità data dagli fps).

Nel file di script basta che ti crei una FUNC_S1 tipo questa:

CODICE
func void Board_S1()
{
       var C_Npc her;
       her = Hlp_GetNpc(PC_Hero);
       if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(her))
       {
               self.aivar[AIV_INVINCIBLE] = TRUE;
               PLAYER_MOBSI_PRODUCTION = MOBSI_Board;
               AI_ProcessInfos(her);
       };
};


E i dialoghi devono avere per npc l'istanza dell'eroe, e la condizione PLAYER_MOBSI_PRODUCTION == MOBSI_Board (invece di board quello che ti pare).

Per rendere effettive le modifiche alle animazioni ti faccio l'esempio di g2 perché non sono esperto delle animazioni di g1 anche se sono quasi uguali:
Io elimino i file humans.msb e humans.mdh compilati (file responsabili solo della gestione, non contengono alcuna animazione). Poi nella cartella anims metto il file humans.mds modificato e il file hum_body_naked.asc che è la mesh degli npc. Poi lanci gothic e compilerà il tutto. Eventualmente se da problemi con le animazioni al primo avvio fallo crashare (quindi non da "esci dal gioco") e riavvia.


Per quanto riguarda la decompilazione si chiama decdat.


Per i mostri parlanti, devi crearli come gli umani, ma cambiare solo e soltanto la visuale. Quindi no gilda da mostro, no routine da mostro. Ti faccio un esempio:

CODICE
instance NpcMostro(Npc_Default)
{
       name[0] = "NpcMostro";
       guild = GIL_NONE;
       id = 121;
       // questi sotto non sono necessari, usa i tuoi
       flags = NPC_FLAG_IMMORTAL;
       npcType = NPCTYPE_FRIEND;
       aivar[AIV_ToughGuy] = TRUE;
       aivar[AIV_ToughGuyNewsOverride] = TRUE;
       aivar[AIV_IGNORE_Murder] = TRUE;
       aivar[AIV_IGNORE_Theft] = TRUE;
       aivar[AIV_IGNORE_Sheepkiller] = TRUE;
       aivar[AIV_IgnoresArmor] = TRUE;
       //////
       B_SetAttributesToChapter(self,0);
       fight_tactic = FAI_HUMAN_COWARD;
       Mdl_SetVisual(self,"HumanS.mds");
       Mdl_ApplyOverlayMds(self,"humans_skeleton.mds");
       Mdl_SetVisualBody(self,"Ske_Body",DEFAULT,DEFAULT,"",DEFAULT,DEFAULT,-1);
       daily_routine = Rtn_Start_121;
};


Quindi niente guild = GIL_WOLF, né start_aistate che sono tipiche dei mostri. Cambia solo le funzione MDL.

Inoltre crea direttamente l'istanza e falla ereditare da Npc_Default se ci sta in gothic 1
 
Top
view post Posted on 31/3/2017, 14:31     +1   -1
Avatar

Advanced Member

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

Status:


Ok, capito tutto...appena riprendo in mano gli script provo entrambe le soluzioni. Grazie ;).

Sai se esiste una funzione che teletrasporta un npc nelle tue vicinanze (non ad un WP preciso)? E poi esiste un modo per far sparire proprio un npc?

EDIT:
Ho provato a creare il lupo come se fosse un npc normale:

CITAZIONE
instance PcHeroFriend_Wolf(Npc_Default)
{
name[0] = "Lupo addestrato";
npcType = NPCTYPE_FRIEND;
guild = GIL_None;
level = 0;
id = 10;
attribute[ATR_STRENGTH] = 40;
attribute[ATR_DEXTERITY] = 40;
attribute[ATR_HITPOINTS_MAX] = 80;
attribute[ATR_HITPOINTS] = 80;
attribute[ATR_MANA_MAX] = 0;
attribute[ATR_MANA] = 0;
protection[PROT_BLUNT] = 20;
protection[PROT_EDGE] = 20;
protection[PROT_POINT] = 10;
protection[PROT_FIRE] = 10;
protection[PROT_FLY] = 0;
protection[PROT_MAGIC] = 0;
Mdl_SetVisual(self,"Wolf.mds");
Mdl_SetVisualBody(self,"Wol_Body",DEFAULT,DEFAULT,"",DEFAULT,DEFAULT,-1);
fight_tactic = FAI_WOLF;
daily_routine = Rtn_follower_10;
};

func void Rtn_follower_10()
{
TA_FollowPC(0,0,23,0,"OC1");
TA_FollowPC(23,0,24,0,"OC1");
};

Però quando lo spawno, rimane immobile e non reagisce per niente. Entro nel suo corco (con il tasto "O") e non riesco proprio a muovermi, ma solo ruotarmi con il mouse. È come se non sa che animazioni usare per farlo muovere.

Edited by Mr.Slash - 31/3/2017, 18:50
 
Top
view post Posted on 31/3/2017, 18:16     +1   -1

Gothic Modder

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

Status:


Per la posizione puoi provare a creare una variabile oCNpc del pg, e modificare la proprietà
trafoObjToWorld[16]; // 0x003C zMATRIX4

Che è una matrice 4x4 (di cui mi pare gli ultimi 4 sono nulli), che rappresentano in qualche modo la matrice delle rotazioni di eulero. Non so di preciso la relazione, però quando ho fatto gli incantesimi AoE a linea retta ho dovuto capire un po' come funzionasse, e per quello che serve a te questi sono i valori che ti interessano:

CITAZIONE
X position = trafoObjToWorld[3]
Y position = trafoObjToWorld[7]
Z position = trafoObjToWorld[11]

CODICE
var oCNpc a; a = Hlp_GetNpc(npc);
var oCNpc b; b = Hlp_GetNpc(hero);

a.trafoObjToWorld[3] = addf(b.trafoObjToWorld[3], addf(mkf(Hlp_Random(10)),mkf(1)));
...


Praticamente pongo la posizione delle x di a uguale a quella di b e aggiungo un po' di randomicità. Ti potrò sembrare un po' strano il modo in cui l'ho scritto, ma questi valori sono decimali, e daedalus non supporta i decimali se non come costanti (1.4,1.5,ecc..). Per farci delle operazioni devi usare il pacchetto float (che dovrebbe esere insieme ad ikarus). L'utilizzo è semplice perché ad ogni operazione corrisponde una funzione, dovrai solo stare attento alle parentesi:

Questo è quello che devi capire:
Tali float non sono propriamente delle variabili float, ma sono intere. Questo perché daedalus non supporta i float, però sono codificati in una particolare rappresentazione. Fai una prova con print(inttostring(mkf(4))). Vedrai che sono interi, però gothic li interpreta come decimali.

mkf(x) = make x float

quando dovrai fare delle operazioni con interi e decimali, l'intero lo dovrai sempre prima convertire in float con questa funzione; io l'ho usato su mkf(hlp_random(10)) perché hlp_random ritorna un intero

addf(x,y) = x + y

il resto lo vedi nella documentazione. Ti scrivo cosa ho fatto in pseudocodice:

a[x_pos] = b[x_pos] + 1 + Random(10)

Così si sposterà nella zona dell'eroe ma mai precisamente sopra. I numeri sono in centimetri, quindi regolati te (io mi terrai ad almeno mezzo/un metro di distanza). Puoi anche evitare il random e metterci un valore preciso

Non è testato ma dovrebbe funzionare.


Per "eliminare" un npc, come intendi te non si può. Bisogna ucciderlo e teletrasportarlo:
In gothic2:
CODICE
B_KillNpc(npc)
AI_Teleport(np,"TOT")


Tot è un waypoint generalmente in una zona inaccessibile
 
Top
view post Posted on 31/3/2017, 18:25     +1   -1
Avatar

Advanced Member

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

Status:


E per quanto riguarda il problema dell'NPC che non da segni di intelligenza?
 
Top
view post Posted on 31/3/2017, 20:16     +1   -1

Gothic Modder

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

Status:


Non ne ho idea, senza sapere come hai proceduto non posso fare ipotesi. Guarda attentamente rouine già fatte compreso l'interno delle funzioni
 
Top
view post Posted on 31/3/2017, 20:52     +1   -1
Avatar

Advanced Member

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

Status:


Ho proceduto come mi hai detto tu. Ho provato anche a mettere al posto di follow ho messo start. Ho provato a cambiare fight tattic, NPC type e non so che altro, ma non ho risolto. Non é che potresti provare ad aggiungere un animale che ti segue in gothic 2 con il tuo modo? Casomai non si può fare basandosi su NPC_Default
 
Top
view post Posted on 2/4/2017, 09:28     +1   -1

Gothic Modder

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

Status:


Si ma mi devi rimettere il codice se fai dei cambiamenti
 
Top
view post Posted on 2/4/2017, 10:34     +1   -1
Avatar

Advanced Member

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

Status:


Potresti provare comunque? Cosi magari, se ti funziona, mi baso sullo script tuo e capisco cosa non va

Edit: Ho trovato il comando Wld_RemoveNpc(npc) ma non so cosa fa. L'ho implementata nella mod per far sparire un'npc, ma non fa niente. Cosa fa secondo te?

Edited by Mr.Slash - 2/4/2017, 17:43
 
Top
view post Posted on 1/6/2017, 11:38     +1   -1
Avatar

Advanced Member

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

Status:


Cmq ho provato a fare come hai detto tu per la bacheca, ma non funziona. I miei passaggi sono questi:

Estraggo dal vdf il file Humans.msb e lo edito con notepad++ le righe che hai scritto tu modificando il nome della funzione S1 al posto di board. Fatto ciò salvo e metto il file humans.mds nella cartella anims da compilare e in seguito avvio il gioco. L'eroe ha lo stesso problema di prima, e cioè che, quando interagisco con il mob si ritrova parallelo al terreno. Quale puo essere il problema?

Cmq per creare la bacheca, ho modificato il file asc della sedia, cioè modifico la sedia e la faccio diventare una bacheca. Logicamente cambio anche il nome della mesh

Edit: mi sono dimenticato di dirti che usce questo errore quando inserisco la bacheca nello spacer (però compare ugualmente):

D: zModel(zCModelProto::ReadGeomobj)
: more than 1 'BIP01' rootNode in hierarchy: ZS_POS0_DIST

Edited by Mr.Slash - 1/6/2017, 15:09
 
Top
view post Posted on 2/6/2017, 15:37     +1   -1

Gothic Modder

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

Status:


L'np prima ammazzalo e poi provalo a rimuovere. Se non va semplicemente è una funzione inutile (come altre). In g2 in realtà quando li fai sparire prima li ammazzi e poi li teletrasporti ad un waypoint lontano nascosto che si chiama TOT.

Il fatto che si mette parallelo al terreno può forse essere un problema di mesh? Da quell'errore pare sì, che ci sta più di un nodo BIP01. Controlla un po', vedi se nell'armatura dell'animazione c'è più di un BIP01, o c'è qualche nodo non connesso (direttamente o indirettamente ad esso)
 
Top
view post Posted on 2/6/2017, 15:43     +1   -1
Avatar

Advanced Member

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

Status:


Io ho modificato il file ASC della sedia e non aveva nessuna armatura la figura umana e neanche un collegamento visibile tra le due mesh. Come hai creato tu in blender questo file ASC della bacheca?
 
Top
27 replies since 18/2/2015, 15:52   708 views
  Share