Script pour s'assoir au minimum à 2 sur un banc.
Ce script gère également les chaises, trônes, fauteuils, tabourets.
Avant de s'assoir, un test est effectué pour savoir si la place convoité est libre ou occupée. Le PNJ/PJ ne pourra pas s'assoir sur une place occupée. Le script réduira de lui-même le nombre de places assises si l'espacement de 0.75m entre chaque place n'est pas respecté.
Merci à
NWNGimly pour son script "S'assoir sur une chaise"sur lequel j'ai basé le mien
1) Créer une zone
2) Placer bancs, chaises, etc ...
3) Editer les propriétés bancs, chaises, etc ...
4) Dans les propriétés des chaises, banc, ... , mettre
"Utilisable" à TRUE,
"Statique" à FALSE
"Collisions" à FALSE
"Script déclenché par l'utilisation" : le script ci-dessous.
Pour faire un banc à 3 places (et plus) :
- Dans les propriétés du banc
1) Changer l'échelle, par exemple en 2,1,1 (la longueur sera doublée)
2) Dans la zone script : éditer des variables et mettre
type / nom / valeur
int / iPlacesMax / 4
float / fTailleBanc / 4,2
Vous aurez un banc à 4 places
Espacement minimal entre les places assises : 0.75m
/////////////////////////////////////////////
// Utilisation d'un Plaçable //
// //
// Script à placer dans "OnUsed" //
// (ou "Script déclanché à l'utilisation") //
/////////////////////////////////////////////
//#include "of_librairie"
///////////////////////////
// Renvoi un vecteur nul //
///////////////////////////
//ENTREE : aucune donnees.
//RETOUR : Vecteur nul (Vector(0.0, 0.0, 0.0) - VectorNul.x=0, VectorNul.y=0, VectorNul.z=0).
vector VectorNul=Vector(0.0, 0.0, 0.0);
///////////////////////////////
// Renvoi une location nulle //
///////////////////////////////
// ENTREE : oArea : la zone concernee (defaut : OBJECT_INVALID)
// RETOUR Location nulle (Location(oArea, Vector(0.0, 0.0, 0.0), 0.0)).
location LocationNulle(object oArea=OBJECT_INVALID)
{
return Location(oArea, VectorNul, 0.0);
}
///////////////////////////////////////
// Normaliser la valeur de l'angle //
///////////////////////////////////////
// ENTREE : fAngle : Angle a normaliser (fAngle<0.0 ou fAngle>360.0)
// RETOUR : 0.0<= fAngle <360.0
float AngleNormalise(float fAngle=0.0)
{
//if (fAngle>=0.0) && (fAngle<360.0) return fAngle;
while (fAngle<0.0) fAngle=fAngle+360.0;
while (fAngle>360.0) fAngle=fAngle-360.0;
return fAngle;
}//FIN Normaliser un angle
////////////////////////////////////
// Renvoi une location distance //
////////////////////////////////////
// Renvoi une position par rapport a l'orientation de l'objet source et la distance souhaitee
//
// ENTREE : oSource : Objet de référence
// fDist : Distance souhaitée entre oSource et la Location
// fHauteur: Hauteur souhaité de la Location
// si fHauteur<=-100.0 alors fHauteur = hauteur de oSource
// fAngleLoc : Si <0.0, la location sera devant l'objet. Sinon elle fera une angle de fAnglePos par rapport à GetFacing(oSource). (0.0 <= fOrient <= 359.99...)
// fFacingLoc : Direction que regarde la location.
// Si fFacingLoc = -1.0 : fFacingLoc=GetFacing(oSource)
// Sinon 0<= fFacingLoc <360
//
// RETOUR : La position souhaitee
//
//
//
// (S) = oSource
// (L) = Location résultant de la fonction
// Le cercle représente la limite definit par fDist
// (x) = GetFacing(oSource) ou fOrient (si >0)
//
// (x) = Direction que (x) = Direction que regarde (S) (x) = Direction que regarde (S)
// regardent (S) et (L) (A) = Direction que regarde (L) (A) = Direction servant a positionner (L)
// (orientation de (S) & (L)) et servant a positionner (L) (B) = Direction que regarde (L) (Orientation de (L))
// (orientation de (L)) Si fFacingLoc<0.0 : (B) = (A)
// Si fFacingLoc>=0.0 : (B) = fFacingLoc
//
// (x) (A) (x) (A) _(B) (x)
// \ \ / \ _/ /
// \ _____ \ _____ / \ / _____ /
// (L) * (L) * (L) *
// * \ * * \ / * * \ / *
// * \ * * \ / * * \ / *
// * \ * * \ / * * \ / *
// * \ * * \ / * * \ / *
// * \ * * \ / * * \ / *
// * (S) * * (S) * * (S) *
// * * * * * *
// * fFacingLoc=-1.0 * * fFacingLoc=-1.0 * * (B)=fFacingLoc *
// * fAngleLoc=-1.0 * * fAngleLoc=(A) * * fAngleLoc=(A) *
// * * * * * *
// * * * * * *
// * _____ * * _____ * * _____ *
//
//
// Exemple
// -------
// \
// (L)--* (b)
// / / - Un objet (oSource) est positionné dans une zone et est orienté vers (a).
// / - On veut placer un autre objet (oObj2) à une distance de 2.0, à 45° et de même hauteur que oSource, et orienté vers (b)
// (a) / (L) est la future position de oObj2 orienté vers (b)
// | / Location lLoc=LocationDistante(oSource, 2.0, -100.0, GetFacing(oSource)-45.0, GetFacing(oSource)-90.0);
// /|\ / object oObj2=CreateObject(nObjectType, sTemplate, lLoc);
// +----|-/--+
// | ./ | oObj2 sera crée à la même hauteur de oSource
// +---------+
// Objet source
//
location LocationDistante(object oSource=OBJECT_SELF, float fDist=0.0, float fHauteur=-100.0, float fAngleLoc=-1.0, float fFacingLoc=-1.0)
{
float fDest=GetFacing(oSource);
if (fAngleLoc>=0.0) fDest=fAngleLoc;
vector vDest = GetPosition(oSource)+AngleToVector(fDest)*fDist;
if (fFacingLoc<0.0) fFacingLoc=fDest;
if (fHauteur>-100.0) vDest.z = fHauteur;
return Location(GetArea(oSource), vDest, fFacingLoc);
}//Fin Location distante
//////////////////////////////////////////////////
// Comme "PlayCustomAnimation" mais sans retour //
//////////////////////////////////////////////////
//Permet d'insérer la commande dans un "DelayCommand"
void PlayCustomAnimationVoid( object oObject, string sAnimationName, int nLooping, float fSpeed = 1.0f)
{
int iPCA=PlayCustomAnimation(oObject, sAnimationName, nLooping,fSpeed = 1.0f);
}
////////////////////////////////////////////////////
// Assoir la créature sur un siège (version NWN2) //
////////////////////////////////////////////////////
// ENTREE : oCreature : Le P(N)J à assoir.
// lSiege : La location du siège.
void AssoirCreature(object oCreature, location lSiege)
{
AssignCommand(oCreature, JumpToLocation(lSiege));
AssignCommand(oCreature, PlayCustomAnimationVoid(oCreature, "sitidle", 1));
AssignCommand(oCreature, SetFacing(GetFacingFromLocation(lSiege)));
}
/////////////////////////////////////////////
// Vérifie que le siège convoité est libre //
/////////////////////////////////////////////
// ENTREE : lSiege : la location du siège.
// RETOUR : La créature qui occupe le siège.
// Renvoi OBJECT_INVALID si le siège est libre.
object PlaceLibre(location lSiege)
{
return GetFirstObjectInShape(SHAPE_SPHERE, 0.2, lSiege);
}
////////////////////////
// SCRIPT PRINCIPAL //
////////////////////////
void main()
{
// Liste des intervenants :
// ------------------------
object oPlaceable=OBJECT_SELF; //Objet lui-meme
object oArea=GetArea(oPlaceable); //La zone ou se situe l'objet
object oOpen=GetLastOpenedBy(); //Celui qui ouvre l'objet
object oClose=GetLastClosedBy(); //Celui qui ferme l'objet
object oUnlock=GetLastUnlocked(); //Celui qui deverouille l'objet (si ferme a cle)
object oLock=GetLastLocked(); //Celui qui verouille l'objet
object oDisturb=GetLastDisturbed(); //Celui qui tente de voler le contenu de l'objet
object oAttaker=GetLastAttacker(oPlaceable); //Celui qui tente de detruire l'objet
object oDamager=GetLastDamager(oPlaceable); //Celui qui a endommage l'objet
object oSpellCaster=GetLastSpellCaster(); //Celui qui jette un sort sur l'objet
object oSpellItem=GetSpellCastItem(); //L'objet qui jette un sort sur l'objet cible
object oClick=GetClickingObject(); //Celui qui clique sur l'objet
object oUser=GetLastUsedBy(); //Celui qui utilise l'objet
object oItemDisturb=GetInventoryDisturbItem(); //L'objet causant le derangement
object oPossessor=GetItemPossessor(oItemDisturb); //Le possesseur de l'objet
object oItem;
string sTag=GetTag(oPlaceable);
string sTagMaj=GetStringUpperCase(sTag);
string sNom=GetName(oPlaceable);
string sNomMaj=GetStringUpperCase(sNom);
string sPlcResRef=GetResRef(oPlaceable);
location lPlcLoc=GetLocation(oPlaceable);
/////////////
// Exemple //
/////////////
//Debug("Nb Var : "+IntToString(GetVariableCount(oPlaceable)));
if (FindSubString(sTag, "XXXXXX")!=-1)
{
//Code...
}
//////////////////////////////////
// Chaises, tabourets et trônes //
//////////////////////////////////
// NWN2 : Pour le modèle "Chaise {04}" (tabouret), penser à baisser l'assise, sinon vous allez l'avoir dans le milieu du ventre à l'utilisation
// Dans les propriétés des chaises : Mettre "Accessible", "Utilisable" à TRUE, "Statique" à FALSE, "Collisions" à FALSE
// "Script déclenché par l'utilisation" : ce script.
// Remarque : Trône {Stone 01 (X1)} pour Géant.
if ((FindSubString(sTagMaj, "CHAIR")!=-1) || (FindSubString(sTagMaj, "STOOL")!=-1) || (FindSubString(sTagMaj, "THRONE")!=-1))
{
//Version NWN2
if (PlaceLibre(GetLocation(oPlaceable))==OBJECT_INVALID) //Verifier que le siège n'est pas occupé
{
float fOrient=180.0;
location lLoc;
if (FindSubString(sPlcResRef, "chair05")!=-1) fOrient=0.0; //Modèles avec une orientation non standard (nwn2)
if ((FindSubString(sPlcResRef, "samarach")!=-1) || (FindSubString(sPlcResRef, "estatestool")!=-1)) fOrient=90.0; //Modèles avec une orientation non standard (nwn2)
if (FindSubString(sPlcResRef, "temp_throne")!=-1) //Modèle trône avec panneau arrière (nwn2)
lLoc=LocationDistante(oPlaceable, -0.9, -100.0, AngleNormalise(GetFacing(oPlaceable)+55.0), GetFacing(oPlaceable) + fOrient);
else lLoc = Location(GetArea(oPlaceable), GetPosition(oPlaceable), GetFacing(oPlaceable) + fOrient);
AssoirCreature(oUser, lLoc);
//PlaySound("as_dr_woodmedop1");
}
return;
}//FIN S'assoir sur une chaise
//////////////////////////////////////
// Banc (s'assoir à plusieurs) NWN2 //
//////////////////////////////////////
// Nnw2 : Dans les propriétés : Mettre "Accessible", "Utilisable" à TRUE, mettre "Statique" à FALSE.
// "Script déclenché par l'utilisation" : ce script.
// Dans les propriétés des bancs : Mettre "Accessible", "Utilisable" à TRUE, "Statique" à FALSE, "Collisions" à FALSE
// "Script déclenché par l'utilisation" : ce script.
// .
// /|\ (Facing)
// |
// +-------------+
// \_____________\
// Banc | < 5 4 3 2 1 |\
// +-------------+
// \ \
// Emplacements des sièges (orientation : facing + 180.0)
//
// Variables locales à placer dans les paramètres du banc (facultatif)
// +-------+-------------+--------+--------------------------------------------------------------------------------------+
// | Type | Nom | Valeur | Description |
// +-------+-------------+--------+--------------------------------------------------------------------------------------+
// | int | iPlacesMax | 2 | Nb de places max (min : 2) |
// | float | fTailleBanc | 2.1 | Taille du banc (min : 2.1) |
// | | | | (modèles les plus petits avec accoudoirs (bench02 et 04)) |
// | | | | Taille réelle du modèle le + petit : 1.9 |
// +-------+-------------+--------+--------------------------------------------------------------------------------------+
// Si aucune variable n'est placée dans le paramètres, ce sera alors un banc à 2 places
// Les valeurs min sont aussi les valeurs par défaut
// L'espacement minimal entre 2 P(N)J est de 0.75, donc pour un banc à 3 places, il faut une longueur de 2.25 (3 x 0.75)
if (FindSubString(sNomMaj, "BANC")!=-1)
{
int iPlacesMax=GetLocalInt(oPlaceable, "iPlacesMax"); //Recupère le nb de places max
float fTailleBanc=GetLocalFloat(oPlaceable, "fTailleBanc"); //Récupère la taille du banc
float fOrient=180.0, fDistSiege, fTailleSiege; //Distance entre les places
location lPlace, lPlaceLibre=LocationNulle();
if ((FindSubString(sPlcResRef, "bench02")!=-1) || (FindSubString(sPlcResRef, "bench04")!=-1)) fOrient=0.0; //Modèles inversés en orientation (nwn2)
if (!GetLocalInt(oPlaceable, "iSiegeOK")) //Les places assises ont été définie ?
{//NON : Création des assises pour le banc
if (iPlacesMax<1) iPlacesMax=2; //Nb places max par défaut
if (fTailleBanc<=2.1) fTailleBanc=2.1; //Taille du banc par défaut
fTailleSiege=fTailleBanc/IntToFloat(iPlacesMax); //Taille de la place assise
//Sécurité : vérifier la taille limite du siège pour pouvoir s'assoir correctement
while (fTailleSiege<0.75) //Espacement mini entre personnnage respecté ?
{//NON : réduire nombre de places
iPlacesMax--;
if (iPlacesMax>0) fTailleSiege=fTailleBanc/IntToFloat(iPlacesMax);
else {fTailleSiege=0.75; iPlacesMax=1;} //Sécurité "division par 0"
}
SetLocalInt(oPlaceable, "iPlacesMax", iPlacesMax);
vector vPosBanc=GetPosition(oPlaceable);
float fPlace=(fTailleBanc/2.0)-(fTailleSiege/2.0); //Position de la 1ere place.
while (iPlacesMax>0)
{//Création des places
lPlace=LocationDistante(oPlaceable, fPlace, vPosBanc.z, AngleNormalise(GetFacing(oPlaceable)+90.0), AngleNormalise(GetFacing(oPlaceable)+fOrient));
SetLocalLocation(oPlaceable, "lPlace"+IntToString(iPlacesMax), lPlace); //Enregistre l'emplacement sur le banc
/*
//Debug visuel
CreateObject(OBJECT_TYPE_PLACED_EFFECT, "n2_fx_torchglow", lPlace); //Pose une flamme sur lPlace
*/
fPlace=fPlace-fTailleSiege;
iPlacesMax--;
}
SetLocalInt(oPlaceable, "iSiegeOK", TRUE); //Les places de ce banc ont été traitées : cette section du script ne sera plus exécuté lors de la prochaine utilisation
iPlacesMax=GetLocalInt(oPlaceable, "iPlacesMax"); //Enregistre le nb de places max réelles pour ce banc
} //else Debug("Ce banc possède déjà ses places.");
//Chercher une place libre sur le banc
int iRechPlace=1, iFin=FALSE;
object oOccupant;
//Debug("Recherche une place disponible.");
while (!iFin)
{
lPlace=GetLocalLocation(oPlaceable, "lPlace"+IntToString(iRechPlace)); //Recupère la position d'une place
oOccupant=PlaceLibre(lPlace);
if (oOccupant==OBJECT_INVALID) //Place dispo ?
{//OUI : arrêter la recherche
lPlaceLibre=lPlace;
iFin=TRUE;
//Debug(ColorString("Place "+IntToString(iRechPlace)+" disponible.", 0,255,0));
} //else Debug(ColorString("Place "+IntToString(iRechPlace)+" occupée par "+GetName(oOccupant),255,0,0));
iRechPlace++;
if (iRechPlace>iPlacesMax) iFin=TRUE; //Toutes les places sont prises
}
if (lPlaceLibre!=LocationNulle()) AssoirCreature(oUser, lPlaceLibre); //Il y a une place dispo : assoir le P(N)J dessus
return;
}//FIN S'assoir sur un banc
}//FIN DU SCRIPT PRINCIPAL
Un exemple en image :
J'ai posé des variables sur le banc pour qu'il ai 3 places
iPlacesMax = 3
fTailleBanc = 2.3
1) Un PNJ va utiliser le banc
2) Le PNJ est assis sur la 1ere place dispo
3) J'utilise le banc -> je m'assois à côté du PNJ (le script me place automatiquement sur une place dispo : la 2eme
4) J'utilise le banc à nouveau : comme le pnj occupe la 1ere place et moi la 2eme, le scripte me déplace à la 3eme place qui était dispo.