La Bibliothèque de Neverwinter Nights
Aide et informations diverses sur Neverwinter Nights ainsi que D&D3.
La date/heure actuelle est 23/11/2024 21:46:14


  Page 1 sur 1 ¤

Voir le sujet précédent ¤ Voir le sujet suivant 
Auteur Message
lylver
Héros
Inscrit le: 08 Avr 2005
Messages: 274
Répondre en citant
Posté le : 06/03/2006 14:10:36 Sujet du message : Travailler avec les fichiers 2da, le golem de chair

Bonjour, on peut extraire pleins d'informations intéressantes des fichiers de paramétrage du jeu.
Mais un petit problème est l'accès laborieux à ces données. Georg Zoeller a prévu le coup pour certaines des fonctions qu'il a créé en mettant "en cache" des fichiers complet 2da en variables locales.
Ici ce n'est pas mon problème exactement, mais je vous propose un script d'effets spéciaux sur le golem de chair (cela rapellera des souvenirs aux joueurs sur table).
3 points à regarder :
l'utilisation des scripts OnUserDefined sur les créatures
la mise en cache des données à accès lent
la manipulation des fichiers 2da


Tout d'abord, activer l'utilisation du script OnUserDefined :

Dans le script OnSpawn de la créature (un golem de chair personnalisé) décommenter les éléments suivants et sauvegarder votre script OnSpawn spécialisé sous un nom à vous :
NWScript :

    // * Fire User Defined Event 1006
    // *
    SetSpawnInCondition(NW_FLAG_DAMAGED_EVENT);

    // * Fire User Defined Event NW_FLAG_SPELL_CAST_AT_EVENT (1011)
    // *
    SetSpawnInCondition(NW_FLAG_SPELL_CAST_AT_EVENT);
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.


Ensuite régler votre module pour une "mise en cache" de données. Dans le script gérant OnModuleLoad ajouter les lignes suivantes :
NWScript :

// Fonction de mise en cache des 2da
  object o2da = GetWaypointByTag("DB_2DA");
  if( GetIsObjectValid(o2da) ){
      WriteTimestampedLogEntry("Successul get of DB_2DA object");
      SetLocalObject(oMod,"DB_2DA",o2da);
    } else {
      WriteTimestampedLogEntry("Fatal Error : unable to get DB_2DA object");
      EndGame("");
    }
//
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.


et créer dans une des zones du module (votre zone d'arrivée c'est pas mal) un point de passage avec le TAG "DB_2DA".

Dernière étape : examinez ce script OnUserDefined
NWScript :

//:: ////
//:: Updated 2006-03-04
//:: capacite du Golem de Chair
//:: ////
#include "nw_i0_generic"
#include "x2_i0_spells"
#include "x0_i0_anims"
// Uses Get2DAString + Cache

int GetSpellInnateLevel(int nSpell, object o2da)
{
  int nLevel = GetLocalInt(o2da,"spellsInnate"+IntToString(nSpell));
  if( nLevel == 0 ){
      nLevel = 1 + StringToInt(Get2DAString("spells","Innate",nSpell)) ;
      SetLocalInt(o2da,"spellsInnate"+IntToString(nSpell),nLevel);
  }
  return nLevel-1 ;
}

string GetSpellImmunityType(int nSpell, object o2da)
{
  string sImmunity = GetLocalString(o2da,"spellsImmunityType"+IntToString(nSpell));
  if( sImmunity == "" ){
      sImmunity = Get2DAString("spells","ImmunityType",nSpell) ;
      SetLocalString(o2da,"spellsImmunityType"+IntToString(nSpell),sImmunity);
  }
  return sImmunity ;
}

void main()
{
  object o2da = GetLocalObject(GetModule(),"DB_2DA");
  SendMessageToAllDMs("OnUserDefined : Golem : no"+IntToString(EVENT_SPELL_CAST_AT));
    // enter desired behaviour here
  switch (GetUserDefinedEventNumber()) {
      case EVENT_SPELL_CAST_AT : {
        object oCaster = GetLastSpellCaster();
/*        int nDmg = GetCasterLevel(oCaster) ;
        if (nDmg > 120) nDmg = 12 ; // item ...    */

        int nSpell = GetLastSpell();
        int nLevel = GetSpellInnateLevel(nSpell,o2da) ;
      // sorts de froid : ralentit
        if( GetSpellImmunityType(nSpell,o2da) == "Cold" ){
            effect eSlow1 = EffectSlow();
            effect eVis1 = EffectVisualEffect(VFX_DUR_ICESKIN);
            effect eLink1 = EffectLinkEffects(eVis1,eSlow1);
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink1, OBJECT_SELF, 18.0f);
            SendMessageToAllDMs("Slow : Golem");
        }
        if( GetSpellImmunityType(nSpell,o2da) == "Electricity" ){
            //Search for and remove the above negative slow effects
            effect eLook = GetFirstEffect(OBJECT_SELF);
            while(GetIsEffectValid(eLook)) {
              if( GetEffectType(eLook) == EFFECT_TYPE_SLOW ||
                  GetEffectType(eLook) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE ) {
                  RemoveEffect(OBJECT_SELF, eLook);
                  SendMessageToAllDMs("Remove Slow : Golem :");
              }
              eLook = GetNextEffect(OBJECT_SELF);
            }
            // Heal Golem
              effect eHeal2 = EffectHeal(nLevel) ;
              effect eVis2 = EffectVisualEffect(VFX_IMP_LIGHTNING_S);
              effect eLink2 = EffectLinkEffects(eVis2,eHeal2);
              ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink2, OBJECT_SELF);
              SendMessageToAllDMs("Heal : Golem :"+IntToString(nLevel));
        }
      }
      case EVENT_DAMAGED : {
        object oEnemy = GetLastDamager(OBJECT_SELF) ;
        int nElec = GetDamageDealtByType(DAMAGE_TYPE_ELECTRICAL) ;
        // Heal Golem
        if (nElec>0) {
            //Search for and remove the above negative slow effects
            effect eLook2 = GetFirstEffect(OBJECT_SELF);
            while(GetIsEffectValid(eLook2)) {
              if( GetEffectType(eLook2) == EFFECT_TYPE_SLOW ||
                  GetEffectType(eLook2) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE ) {
                  RemoveEffect(OBJECT_SELF, eLook2);
                  SendMessageToAllDMs("Remove Slow Elec Effect : Golem :");
              }
              eLook2 = GetNextEffect(OBJECT_SELF);
            }
            effect eHeal3 = EffectHeal(nElec) ;
            effect eVis3 = EffectVisualEffect(VFX_IMP_LIGHTNING_S);
            effect eLink3 = EffectLinkEffects(eVis3,eHeal3);
            ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink3, OBJECT_SELF);
            SendMessageToAllDMs("Heal Elec Effect : Golem :"+IntToString(nElec));
        }
        int nCold = GetDamageDealtByType(DAMAGE_TYPE_COLD) ;
        if (nCold>0) {
            effect eSlow4 = EffectSlow();
            effect eVis4 = EffectVisualEffect(VFX_DUR_ICESKIN);
            effect eLink4 = EffectLinkEffects(eVis4,eSlow4);
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink4, OBJECT_SELF, 18.0f);
            SendMessageToAllDMs("Slow Cold Effect : Golem");
        }
      }
  } /* switch */
}
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.


Vous constaterez un petit lag lors des premiers évênements concernés par les effets de froid et electricité sur ce golem, après celà c'est instantané.
Pour ceux qui sont plus intéressés par l'aspect ludique de la créature : celle-ci est virtuellement immunisée aux sorts d'électricité (sauf dégats massifs ou dépassant ses points de vie restants : "surcharge") et même se soigne des effets de sorts électriques qui lui sont envoyés.
Pour les dégats de froid, un petit effet visuel accompagne le ralentissement temporaire de la créature.
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
lylver
Héros
Inscrit le: 08 Avr 2005
Messages: 274
Répondre en citant
Posté le : 14/03/2006 15:23:45 Sujet du message :

Après des tests :
c'est très long de lire une valeur dans un fichier 2da : j'ai fait des mesures sur 1600 enregistrements (spells.2da) sur un P4-2GHz : 360 secondes (225ms unitaire)
Je suis en train de mettre au point une façon de collecter les informations des 2da dans une database nwn (SetCampaignXX et GetCampaignXX). Les premiers tests me font penser que c'est 300 fois plus rapide de lire dans la DB nwn, c'est pas peu dire...
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
-MeteZ-
Seigneur
Inscrit le: 19 Mar 2006
Messages: 205
Localisation: Région Parisienne (95)
Répondre en citant
Posté le : 22/03/2006 22:14:26 Sujet du message :

C'est simpa, tu fera part de ton fichier campaign ? Parce que moi j'avais fais pareil mais pour les clases.2da avec les noms en francais.
En tout cas merci pour les test de rapidités d'éxecution.
_________________
"Ne dit pas affronter les ténèbres celui qui n'a jamais connu la tombée de la nuit."
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
lylver
Héros
Inscrit le: 08 Avr 2005
Messages: 274
Répondre en citant
Posté le : 23/03/2006 11:16:22 Sujet du message :

Comme indiqué au dessus, je me suis penché sur une optimisation de la chose pour accélérer tout ça.

Une partie du script de Module OnModUserDef
Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :

//:: //
//:: Updated 2006-03-21 Lylver
//:: NWN-FF 4.1.00 used
//:: //
//:: Updated 2006-03-14 Lylver
//:: prefetch 2da Cache
#include "ly_lib_time"
#include "bbs_lib_item" // disponible dans "vos scripts"
#include "ff_include" // optionnel j'utilise maintenant NWN-FF 4.1.00
void main(){
  object oMod = GetModule() ;
  // ajout NWN-FF 21 Mars 2006
  int FFDB = GetLocalInt(oMod,"FFDB");
  //
  switch (GetUserDefinedEventNumber()) {
case 900:{
      // 2da prefetch
      // fetch some 2da from DB or from 2da file
      // create a database for faster prefetch
        object o2da = GetWaypointByTag("DB_2DA");
        int nSpell = GetLocalInt(o2da,"2DA_SPELL");
        int bLoop = TRUE ;
        float fDelay = 12.0;
        while( bLoop ){ //FFDB : test 2*805 fetch
        if( nSpell == ((nSpell / 20) * 20) ){
            bLoop = FALSE;
            fDelay = 1.0;
            WriteTimestampedLogEntry("2da Spell Fetch : nSpell = "+IntToString(nSpell));
        }
        if( nSpell > 805 ){
            WriteTimestampedLogEntry("2da Spell Fetch Completed !");
            break ; // finished !
        }
        int nLevel;
        string sImmunity;
        string sSQL;
        int iRes;
        // Log
        // WriteTimestampedLogEntry(" ;2da Spell Fetch : "+IntToString(nSpell));

//
//  avec NWN-FF
//

        if( FFDB ){
            // Try dDB first
            sSQL = "SELECT Innate FROM 2daSpells WHERE SpellID=" + IntToString(nSpell) ;
            iRes = SQLLocalExecAndFetchDirect(sSQL);
            nLevel = SQLLocalEatDataInt();
            //
            if( nLevel <= 0 ){
              nLevel = 1 + StringToInt(Get2DAString("spells","Innate",nSpell)) ;
              sSQL = "INSERT INTO 2daSpells (SpellID,Innate) VALUES(" +
              IntToString(nSpell) + "," + IntToString(nLevel) +")";
              SQLExecDirect(sSQL);
              bLoop = FALSE; // force le DELAYCOMMAND si lecture 2da : plusieurs passes
            }
            SetLocalInt(o2da,"spellsInnate"+IntToString(nSpell),nLevel);
            //
            sSQL = "SELECT ImmunityType FROM 2daSpells WHERE SpellID=" + IntToString(nSpell) ;
            iRes = SQLLocalExecAndFetchDirect(sSQL);
            sImmunity = SQLLocalEatData();
            //
            if( sImmunity == "" ){
              sImmunity = Get2DAString("spells","ImmunityType",nSpell) ;
              // ajout d'un prefixe #
              sSQL = "UPDATE 2daSpells SET ImmunityType='#" + sImmunity +
              "' WHERE SpellID=" + IntToString(nSpell);
              SQLExecDirect(sSQL) ;
              bLoop = FALSE; // force le DELAYCOMMAND si lecture 2da : plusieurs passes
            } else { // retrait du prefixe #
              sImmunity = GetStringRight(sImmunity,GetStringLength(sImmunity)-1);
            }
            //
            SetLocalString(o2da,"spellsImmunityType"+IntToString(nSpell),sImmunity);
        } else { // no NWN-FF

//
// pour le cas sans NWN-FF
//

            bLoop = FALSE; // force le DELAYCOMMAND : plusieurs passes
            // Try dDB first
            struct MemDB dDB;
            dDB.sDB = "2DA_SPELL";
/* non utile si on utilise pas le systeme de CACHE
            dDB.oChi = GetLocalObject(oMod,"DBI_ READ");
            dDB.oChs = GetLocalObject(oMod,"DBS_ READ");
            dDB.oDbi = GetLocalObject(oMod,"DBI_ FIFO");
            dDB.oDbs = GetLocalObject(oMod,"DBS_ FIFO");
*/

            dDB.sVar = "";
            dDB.nValue = 0;
            dDB.sValue = "";
            //
            dDB.sVar = "Innate"+IntToString(nSpell);
            // nLevel = GCacheInt(dDB) ;
            nLevel = GetCampaignInt(dDB.sDB,dDB.sVar)
            if( nLevel == 0 ){
              nLevel = 1 + StringToInt(Get2DAString("spells","Innate",nSpell)) ;
              dDB.nValue = nLevel ; // SCacheInt(dDB) ;
              SetCampaignInt(dDB.sDB,dDB.sVar,dDB.nValue) ;
            } else {
              fDelay = 0.4;
            }
            SetLocalInt(o2da,"spellsInnate"+IntToString(nSpell),nLevel);
            //
            dDB.sVar = "ImmunityType"+IntToString(nSpell);
            // sImmunity = GCacheString(dDB) ;
            sImmunity = GetCampaignString(dDB.sDB,dDB.sVar) ;
            if( sImmunity == "" ){
              sImmunity = Get2DAString("spells","ImmunityType",nSpell) ;
              dDB.sValue = "#"+sImmunity; // SCacheString(dDB) ;
              SetCampaignString(dDB.sDB,dDB.sVar,dDB.sValue) ;
            } else {
              sImmunity = GetStringRight(sImmunity,GetStringLength(sImmunity)-1);
            }
            //
            SetLocalString(o2da,"spellsImmunityType"+IntToString(nSpell),sImmunity);
        }
        SetLocalInt(o2da,"2DA_SPELL",++nSpell);
        } // while
        // Continue Slow fetch
        if( !(bLoop) ) DelayCommand(fDelay, SignalEvent(OBJECT_SELF, EventUserDefined(900)));
        break ;
      }
}
}
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.

tn_mod_init_db.nss (pour la creation des tables mysql si NWN-FF
Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :

//:Confused/
//:: Created 2006-03-21, isolation tables TNB2
//:Confused/
//:: Updated 2006-03-18, NWN-FF 4.1.00
//:Confused/
//:: Updated 2006-03-16 Lylver, ajout NWN-FF, admin lylver
//:: checked : leave everything, CNR could be useful
///*************************** **********
//* NWN-FF 4.1.10 (c) 2005 FastFrench *
//**************************** *********
#include "ff_include"
void main()
{
// ajout lylver 2006-03-18

SQLExecDirect("CREATE TABLE IF NOT EXISTS `PlayerSpells` ("+
  "`Id` smallint(5) unsigned NOT NULL default '0',"+
  "`SpellUsedCount` tinyint(4) unsigned NOT NULL default '0',"+
  "PRIMARY KEY (`Id`)"+
") TYPE=MyISAM");

// SQLExecDirect("DROP TABLE IF EXISTS `PlayerSpellUsed`");

SQLExecDirect("CREATE TABLE IF NOT EXISTS `PlayerSpellUsed` ("+
  "`Id` smallint(5) unsigned NOT NULL default '0',"+
  "`Number` tinyint(4) unsigned NOT NULL default '0',"+
  "`SpellID` smallint(5) unsigned NOT NULL default '0',"+
  "PRIMARY KEY (`Id`,`Number`)"+
") TYPE=MyISAM");

WriteTimestampedLogEntry("PlayerSpells &amp; PlayersSpellUsed crees");

SQLExecDirect("CREATE TABLE IF NOT EXISTS `2daSpells` ("+
  "`SpellID` smallint(5) NOT NULL default '-1',"+
  "`ImmunityType` varchar(16) NOT NULL default '',"+
  "`Innate` tinyint(4) NOT NULL default '-1',"+
  "PRIMARY KEY (`SpellID`)"+
") TYPE=MyISAM");
}
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.


et pour démarrer tout ça voici un morceau du script OnModuleLoad
Ce message est un spoiler, et risque de vous informer de choses que vous auriez dû apprendre par vous même (fin d'un jeu, film, etc). À vos risques et périls (ludiques), vous pouvez le voir en cliquant sur cet avertissement.
Spoiler :
NWScript :

//:Confused/
//:: Updated 2006-03-16 Lylver, ajout NWN-FF
//:Confused/
//:: Updated 2006-03-14 Lylver
//:: prefetch 2da Cache
//:Confused/
//:: Updated 2006-03-04 Lylver
//:: 2da Cache
//:Confused/

#include "x2_inc_switches"
#include "x2_inc_restsys"
#include "ly_lib_time"
// #include "ly_lib_spell"
#include "bbs_lib_item"
void main()
{
  object oMod = GetModule() ;
  ExecuteScript("tn_mod_set_db", oMod);
  // ajout NWN-FF 16 Mars 2006
  int FFDB = GetLocalInt(oMod,"FFDB");
  WriteTimestampedLogEntry("Initialisation NWN-FF : "+IntToString(FFDB));
  if( FFDB ) ExecuteScript("ff_on_mod_load", OBJECT_SELF);
  // separation 21 Mars 2006
  if( FFDB ) ExecuteScript("tn_mod_init_db", OBJECT_SELF);
  //
// Fonction de mise en cache des 2da
  object o2da = GetWaypointByTag("DB_2DA");
  if( GetIsObjectValid(o2da) ){
      WriteTimestampedLogEntry("Successul get of DB_2DA object");
      SetLocalObject(oMod,"DB_2DA",o2da);
    } else {
      WriteTimestampedLogEntry("Fatal Error : unable to get DB_2DA object");
      EndGame("");
    }
// fetch some 2da
  SetLocalInt(o2da,"2DA_SPELL",0);
  // Start Slow fetch
  SignalEvent(OBJECT_SELF, EventUserDefined(900));
}
Note : le code affiché ci-dessus n'est pas rendu tel qu'il devrait l'être réellement, en particulier des sauts de lignes sont automatiquement insérés pour éviter de casser la mise en page. En le copiant/collant, vous résoudrez ce problème.


Voilà : j'en ai profité pour tout mettre car je fais moi même actuellement la transition entre système CACHEDB et NWN-FF
Je t'ai mis les instructions de façon à te passer de mon CACHEDB
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
lylver
Héros
Inscrit le: 08 Avr 2005
Messages: 274
Répondre en citant
Posté le : 23/03/2006 14:21:56 Sujet du message :

Côté qualitatif par contre, j'ai remarqué des choses bizarres dans spells.2da :
parmi les immunités il y a des champs remplis avec "Positive", "Postive", "Mind-Affecting", "Mind_Affecting", "Mind_Effecting", "1".

Enfin bref, j'ai normalisé tout ça une fois la base créée avec une mise à jour à la main. Je me demande si ce n'est pas la source de bug dans nwn
 
Revenir en haut Voir le profil de l'utilisateur Envoyer un message privé Ignorer l'utilisateur
 
Montrer les messages depuis :
Page 1 sur 1 ¤


Vous ne pouvez pas poster de nouveaux sujets dans ce forum
Vous ne pouvez pas répondre aux sujets dans ce forum
Vous ne pouvez pas éditer vos messages dans ce forum
Vous ne pouvez pas supprimer vos messages dans ce forum
Vous ne pouvez pas voter dans les sondages de ce forum


Sauter vers:
FAQ | Rechercher | Liste des Membres | Groupes d'utilisateurs | S'enregistrer | Profil | Se connecter pour vérifier ses messages privés | Connexion
Powered by phpBB 2.* [m] © 2001, 2002 phpBB Group
Theme rewritten in beautiful XHTML code by Baldurien.
Thème "La Bibliothèque de Neverwinter" crée par Kruger
Traduction par : phpBB-fr.com
Page generated in 140.195ms