[Script] Peuplement de zone

Répondre
Partager Rechercher
Voila mon système de peuplement de zone achevé (version finale). Il permet de spawner des pnjs ou toutes autres créatures par des encounters (ceux de Bioware). Il permet aussi de nettoyer la zone lorsque le dernier joueur la quitte (pnjs crées par encounter et objets laissés à terre après un certain temps).

Il est le plus économique et le plus simple système de génération de PNJ (aucun GetObjectByTag et une seule boucle sur les objets contenus dans la zone). Il se compose de 3 scripts universels qui sont à mettre :

- dans le OnEnter de la zone :
Code PHP:

void main()

 
object oPlayer GetEnteringObject();
 
object oArea OBJECT_SELF;
 if(!
GetIsPC(oPlayer)||GetIsDM(oPlayer)){ return; }

 
// Area decouverte, enlever les commentaires :
 //ExploreAreaForPlayer(oArea, oPlayer);

 // on a affaire a un joueur qui rentre dans notre zone. Si c'est le
 // premier joueur, on fait sorir nos pnjs de derrieres les fagots,
 // sinon, on ne fait rien (les PNJs sont deja la) :

 
int iNumberOfPlayer GetLocalInt(OBJECT_SELF,"AREA_PC_COUNT");
 
// on incremente ca :
 
SetLocalInt(OBJECT_SELF,"AREA_PC_COUNT",iNumberOfPlayer+1);

 
// si le premier joueur vient d'entrer, on indique a nos triggers qu'il faut qu'ils travaillent ...
 
if(iNumberOfPlayer == 0)
 {
  
SetLocalInt(OBJECT_SELF,"TRIGGER_WORK",TRUE);
  }
  else
  {
    
DeleteLocalInt(OBJECT_SELF,"TRIGGER_WORK");
  }

- dans le OnLeave de la zone :
Code PHP:

void TrashObject(object oObject)
{
     
/* search and destroy contents of body bag's, others just destroy */
    
if (GetObjectType(oObject) == OBJECT_TYPE_PLACEABLE) {

        
object oItem GetFirstItemInInventory(oObject);

        
/* recursively trash all items inside container */
        
while (GetIsObjectValid(oItem))
        {
            
TrashObject(oItem);
            
oItem GetNextItemInInventory(oObject);
        }
    }
    
DestroyObject(oObject);
}

void main()
{
 
object oPlayer GetExitingObject();
 
object oArea OBJECT_SELF;
 if(!
GetIsPC(oPlayer)||GetIsDM(oPlayer)){ return; }

 
int iPCCount GetLocalInt(oArea,"AREA_PC_COUNT") - 1;
 
SetLocalInt(oArea,"AREA_PC_COUNT",iPCCount);

/* bypass if currently in-progress (blocked) or ClearTrash is disabled */
 
if (GetLocalInt(OBJECT_SELF"CT_IN_PROGRESS") != 1)
 {

    
SetLocalInt(OBJECT_SELF"CT_IN_PROGRESS"1); /* set a flag to block */

    
int iItemDestructTime;
    
int iObjectType;
    
int iNow = (GetCalendarMonth()*10000) + (GetCalendarDay()*100) + GetTimeHour();
    
int iAreaDestructTime iNow 1;  /* destroy items in 'n' game hours from now */

    
object oItem GetFirstObjectInArea();

    while (
GetIsObjectValid(oItem))
    {
        
// Destruction des PNJs generes automatiquement
        
if(GetIsEncounterCreature(oItem) && (iPCCount==0))
        {
         
DestroyObject(oItem);
         
oItem GetNextObjectInArea();
        }
        else
        {
        
iObjectType GetObjectType(oItem);
        switch (
iObjectType) {
        case 
OBJECT_TYPE_PLACEABLE:

            
/* monster drop containers are tagged placeables */
            
if (GetTag(oItem) != "BodyBag") {
                break; }

            
/* note: no break here, allow fall-through */

        
case OBJECT_TYPE_ITEM:

            
iItemDestructTime GetLocalInt(oItem"CT_DESTRUCT_TIME");

            if (
iItemDestructTime 0)
            {
                if (
iItemDestructTime <= iNow) {
                    
TrashObject(oItem);   /* destruct time has passed, trash the object */
                
}

                
/* note: no action if destruct time set but not passed */

            
} else {

                
/* no destruct time set, so do it now */
                
SetLocalInt(oItem"CT_DESTRUCT_TIME"iAreaDestructTime);
            }
        }


        
oItem GetNextObjectInArea();

       }
    }

    
SetLocalInt(OBJECT_SELF"CT_IN_PROGRESS"0);  /* done, release */

 
}

- dans le OnEnter du trigger de rencontre :
Code PHP:

void main()
{
 
SetEncounterActive(FALSE,OBJECT_SELF);
 if(
GetLocalInt(GetArea(OBJECT_SELF),"TRIGGER_WORK"))
 {
   
// profitez en pour mettre ici d'autres conditions,
   // comme le nombre de PNJs maximum a creer (il sont
   // sans doute moins nombreux la nuit que le jour...)
   // if(GetIsNight()){ SetEncounterSpawnsMax(d4(),OBJECT_SELF); }
    
SetEncounterActive(TRUE,OBJECT_SELF);
 }

Je précise que l'encounter doit avoir comme faction "hostile", bien que les pnjs peuvent être des Defenseurs ou autres. Enfin, mettre en option de spawn "une seule fois" ("one shot").

Voila !

Prince Nexus.
Je vais peut être dire une betise... Mais dans le OnLeave, ne faudrait il pas tester le nombre de PJ restant dans la zone avant de detruire les PNJ? Pour ne pas detruire les PNJ si un PJ est encore présent...
Salut.

Ca me parait un bon systeme si j'ai bien compris ce qu'il faisait.

C'est la même chose q'un systeme d'encounter mais ca permet justement pour des creatures par exemple non tué (ce qui est le cas pour des PNJ) de disparaitre lorsqu'il n'ya plus de joueur dans la zone, et de réaparaitre dès qu'1 nouveau joueur entre dans la zone et active le trigger de rencontre.
Pas mal du tout ça

Ca evite donc du lag je suppose car la zone est vide si il n'y a pas de joueur.
Ca evite que des qu'un joueur passe sur le trigger en question la même creature se superpose à chaque fois sans disparaitre.

Bref c'est un trigger de rencontre amélioré que tu nous as fait là et adapté aux PNJ. Ca doit être pratique pour une ville par exemple.
Coooooool
@Damonya : oui tu as tout compris : c'est sans conteste le meilleur systeme pour gérer tes pnjs (c'est pour ça que je l'ai fait niark !!!). Son seul défaut, c'est qu'il peut générer 8 pnjs maximum par encounter. Qu'a cela ne tienne, tu en mets plusieurs les uns au dessus des autres....

CONSEIL : comme le trigger doit couvrir toute l'area, mieux vaut en dessiner un petit, placer les points de spawn. Puis quand c'est fait, tu redessines le trigger pour qu'il couvre toute la zone.

@Fanley : regarde bien le code... T'inquiète pas, si je dis version finale, c'est que c'est vraiment une version finale (je l'ai testé pas mal de fois et OnLine, c'est que du bonheur = 40% de lag en moins par rapport à une solution avec un placeable et un script sur son OHB - comme le faisaient les autres systemes)

Prince Nexus.
on rajoute la condition de spawn de nuit du trigger

question :

admettons qu'un joueur reste suffisemment dans la zone avec ce système de spawn pour que l'on passe du jour à la nuit et qu'un autre joueur rentre dans la zone la nuit.

qu'est-ce qu'il se passe ?
Citation :
Provient du message de Prince Nexus
@Fanley : regarde bien le code... T'inquiète pas, si je dis version finale, c'est que c'est vraiment une version finale (je l'ai testé pas mal de fois et OnLine, c'est que du bonheur = 40% de lag en moins par rapport à une solution avec un placeable et un script sur son OHB - comme le faisaient les autres systemes)
Mea Culpa, je n'avais pas vu le "&& (iPCCount == 0)" ... Je m'attendais à ce que le test soit fait AVANT d'entrer dans la boucle faut dire Mais je comprends pourquoi c'est fait comme ça: pour vider quand même la zone des objets "jetés"... très écologique comme solution
En effet, les objets de quetes sont effacés s'ils sont au sol. Comme j'utilise le Corps Lootable v.5 pour gérer les corps défunts, je ne m'en occupe pas. On peut rajouter un test sur ces objets en effet. Pour moi, il est redondant.

Prince Nexus.
Citation :
Je précise que l'encounter doit avoir comme faction "hostile", bien que les pnjs peuvent être des Defenseurs ou autres. Enfin, mettre en option de spawn "une seule fois" ("one shot").

Prince Nexus.
Question : Meme en mettant l'option sur une seule fois, il est possible de faire Respawn les monstres aprés un certain temps sans quitter la zone ?
Le principe est que je souhaitais peupler mes zones de villes/villages avec une liste de PNJs aléatoires. Donc dans un premier temps, le joueur entre dans la zone. Si c'est le premier et qu'il marche sur les encounters portant le script ennoncé ci-dessus, les pnjs sont créés. Ils disparaissent ensuite lorsque le dernier joueur quitte la zone et réapparaitront ensuite lorsque à nouveau un joueur y entrera. Je précise bien un joueur car le DM ne déclenche pas les encounters Bioware quels qui soient.

Ce systeme est déconseillé pour gérer les monstres car en effet, si tu mets en option de spawn: "continu", les monstres disparaitront lorsque le dernier joueur quittera la zone. Cependant, si tu modifies le script de l'event OnEnter du trigger de rencontres pour qu'il spawn plusieurs fois les monstres à intervalle de temps régulier, c'est possible. Sache qu'il faut dans ce cas que tu fasses des tests pour savoir si les joueurs ont tué tous les monstres précédemment spawnés et que l'intervalle de temps séparant les 2 spawns est respecté. En clair, c'est galère et ça n'a aucun intéret.

La gestion des monstres par les encounters de Bioware est parfaite et semble la plus économique, il me semble. Pourquoi faire compliquer quand on peut faire simple ?

Prince Nexus
mmmm
peut-être parce que la gestion par encounter bioware ne permet de spawner qu'un maximum de 8 créatures par déclencheur.
ou parce qu'un déclencheur ne permet pas de choisir par script les créatures qui devront apparaître.
ou bien qu'un déclencheur se base sur le CR du personnage qui marche dessus.
et j'en ai d'autres des raisons. Bref, plein de raisons qui font que les encounters bioware ne sont pas adaptés à tous les serveurs NwN, même ceux qui ne se veulent pas mmorpg.
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés