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 :
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 :
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 :
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.