Des zones aléatoires sur BDD

Répondre
Partager Rechercher
Bonjour à tous !

voilà j'ai terminé un script qui a pour but d'améliorer les modules persistants (ou pas )

La reflexion vient de deux constats :
- Le Boss d'un donon, méchant pas beau par excellence, se fait défoncer la tronche 5 à 6 fois par jour pendant des semaines voir des mois.. Il doit donc se douter que son donjon est tout pourri et que les aventuriers le parcours trop facilement ou alors il a vraiment pas de chance et la réunion internationale des Gros Bills se tient juste à côté de chez lui... bref il faut qu'il change son donjon
- Dans une ville les gens gardent la même maison ad vitam eternam...

bref tout ceci entraîne de la monotonie chez le joueur (j'ai été joueur, style GB... et les technique pour éviter tous les pièges genre 2 pas à droite, 4 à gauche et 3 devant, je connais ) et il faut au(x) concepteur(s) beaucoup de travail pour refaire les donjons.. Mais 2eme constats : quand on changeait les donjons, je les redécouvrait avec autant de plaisir qu'un môme qui ouvre ses paquets de noël

donc j'ai fais un script pour que les transitions soient calculées aléatoirement et stockées sur une base de données que l'on peut effacer à tout moment. Il subsiste 1 problèmes et 2 contraintes malheureuses pour le MD

PROBLEME : le joueur apparait face à la porte (ça marche aussi avec des zones de transition) quand il arrive dans la nouvelle zone... je sais pas pourquoi, pourtant j'ai essayé de modifier la direction avec un +180.0 ou -180.0 mais rien n'y fait.. bon au final c'est pas trop grave, le joueur doit se retourner mais bon c'est chiant.. si quelqu'un trouve la solution

CONTRAINTES :
- en générant les zones de transitions aléatoirement, le donjon peut etre tout petit... genre la zone de fin dès le début. Les maisons peuvent être de la même façon gigantesques. Mais le problème n'est que statistique et il suffit de générer assez de zones afin de le limiter. Il se peut aussi qu'il y ait des zones inutilisées (j'expliquerai ensuite comment faire pour limiter ceci)
- Pour éviter les incohérences le donjon ou les maisons doivent soit s'enfoncer soit monter mais pas les deux (les donjons c'est moins grave car s'ils sont magiques c'est possibles).. En gros le truc c'est de décider d'un même système d'étage (les escaliers soit avant, soit après la transitions, mais pas les deux). Sinon on peut se retrouver avec un accès à la cave ou au sous sol par le troisièmes étage


LE SYSTEME : les donjons / maisons / zones sont définies par des portes ou des zones de transitions, et le donjon doit avoir une architecture comme telle : porte de niveau N => porte de niveau n+1. Dans la même zone que la porte n+1, une porte de niveau N => porte de niveau N+1 etc etc..
n peut le faire sur une même grande zone ou bien des zones séparées
Donc les portes d'entrée sont les portes n+1 et les portes de sorties les porte n

On peut faire des cul de sac, avec un partie qu'avec une porte d'entrée. Si on veut exploiter toutes les zones, il faut un nombre de portes n+1 supérieur à des portes de niveau n. (c'est compliqué hein ) un petit schéma grâce à mes talents de dessinateurs impressionants )


http://img144.imageshack.us/img144/4521/donjonaleatij5.th.jpg


LES PREREQUIS

- faire des portes et/ou zones de transitions avec untag de base unique. Rajouter ET pour une entrée de zone à la fin du tag et RC pour une sortie de zone. ensuite numérotée les portes/transitions avec 01, 02, 03, etc

EXEMPLE : une porte avec pour tag de base TAGPORTE
Donc les portes d'entrée auront pour tag TAGPORTEET01, TAGPORTEET02, TAGPORTEET03, etc et les portes de sortie TAGPORTERC01, TAGPORTERC02, TAGPORTERC03, etc..
remarquez que dans ce système la porte d'entrée même du donjon (s'il est complèteent aléatoire) sera une porte de sortie en fait

Mettre le script de base sur le OnClick des portes/transitions

Pour les portes : changer les propriétés et NE PAS METTRE "aucune transition" (pas besoin de renseigner le tag de la cible), sinon l'évenement OnClick ne fonctionnera pas. Bien sûr le Onclick ne fonctionne que sur une porte OUVERTE (donc il faut la dévérouiller et désarmer avant )

J'ai pris des fonctions du script nw_io_position pour les modifier dès que je saurai comment faire se retourner ce joueur

Script de bibliothèque
Code PHP:

// pris de nw_io_position
// **********************************
float GetChangeInX(float fDistancefloat fAngle);
float GetChangeInY(float fDistancefloat fAngle);
vector GetChangedPosition(vector vOriginalfloat fDistancefloat fAngle);
location GenerateNewLocation(object oTargetfloat fDistancefloat fAnglefloat  fOrientation);
// **********************************

// renvoie la location à 130°de la porte ouverte : 130 ° fonctionne avec tout
// devant la porte pour un joueur, c'est en fait derrière pour le programe
location KTXGetBehindDoor (object oTargetfloat fDistance=1.0);


// renvoie "01", "02", "03" depuis un entier 1, 2 , 3
string ComptToString (int iCompt);

// compte le nombre de porte et l'enregistre sur le module
void CalculPorte(string sTag);

// renvoie le résultat d'une boucle décalée aléatoire
int GetBoucle (int iNbBoucleint iRandomBoucleint iBoucleMax);

// non utilisé 
int BackBoucle (int iNbBBoucleint iBBoucleMax);

// renvoi "ET" ou 3RC3 à partir du tag de la porte
string GetTypePorte(object oPorteInit);

// renvoie le tag de base de la porte
string GetTagBase (object obase);

calcul la cible à partir de la porte 
object SetDestination 
(object oPorte);


const 
string sBDD "BASEdeDONNEES";

location KTXGetBehindDoor(object oTargetfloat fDistance 1.0)
{
    
float fDir GetFacing(oTarget);
    
float fAngleOpposite GetFacing(oTarget) - 130.0;
    return 
GenerateNewLocation(oTarget,
                               
fDistance,
                               
fAngleOpposite,
                               
fDir);
}
                               
location GenerateNewLocation(object oTargetfloat fDistancefloat fAnglefloat fOrientation)
{
    
object oArea GetArea(oTarget);
    
vector vNewPos GetChangedPosition(GetPosition(oTarget),
                                        
fDistance,
                                        
fAngle);
    return 
Location(oAreavNewPosfOrientation);
}

vector GetChangedPosition(vector vOriginalfloat fDistancefloat fAngle)
{
    
vector vChanged;
    
vChanged.vOriginal.z;
    
vChanged.vOriginal.GetChangeInX(fDistancefAngle);
    if (
vChanged.0.0)
        
vChanged.= - vChanged.x;
    
vChanged.vOriginal.GetChangeInY(fDistancefAngle);
    if (
vChanged.0.0)
        
vChanged.= - vChanged.y;

    return 
vChanged;
}

// This returns the change in X coordinate that should be made to
// cause an object to be fDistance away at fAngle.
float GetChangeInX(float fDistancefloat fAngle)
{
    return 
fDistance cos(fAngle);
}

// This returns the change in Y coordinate that should be made to
// cause an object to be fDistance away at fAngle.
float GetChangeInY(float fDistancefloat fAngle)
{
    return 
fDistance sin(fAngle);
}

string ComptToString (int iCompt)
{
string sCompt;
if (
iCompt 10sCompt "0" IntToString (iCompt);
else 
sCompt IntToString (iCompt);
return 
sCompt;
}

void CalculPorte (string sTag)
{
string stNb;
int tNb 1;
object oPorte GetObjectByTag (sTag+ComptToString (tNb));
while (
oPorte != OBJECT_INVALID)
    {
    
tNb ++;
    
oPorte GetObjectByTag (sTag ComptToString(tNb));
    }
tNb --;
SetLocalInt (GetModule(),sTag "nb",tNb);
}


// prend une boucle et donne le résultat sur une boucle décalée
// Rajoute iRandomBoucle tout en restant en dessous du max
// sert à se servir d'une fonction aléatoire avec condition
// sans risquer de toujours tomber toujours sur un mauvais objet
int GetBoucle (int iNbBoucleint iRandomBoucleint iBoucleMax)
{
int iResult iRandomBoucle iNbBoucle ;
if (
iResult iBoucleMaxiResult iResult iBoucleMax;
return 
iResult;
}

// revient au résultat initial en partant de la boucle décalé de iNbBBoucle
int BackBoucle (int iNbBBoucleint iBBoucleMax)
{
int iResult iNbBBoucle iBBoucleMax;
if (
iResult <= 0iResult iResult iBBoucleMax;
return 
iResult;
}


string GetTypePorte(object oPorteInit)
{
string sTagoPorte GetTag(oPorteInit);

// prend les caractères 3-4 en partant de la droite pour le style 
// ("RC" et "ET" suivant leurs destinations)
string sType GetStringLeft(GetStringRight(sTagoPorte,4),2);
return 
sType;
}


string GetTagBase (object obase)
{
string sbase GetTag(obase);
string sTagBase GetStringLeft (sbase ,GetStringLength(sbase)-4);
return 
sTagBase;
}



object SetDestination (object oPorte)
{
object oDest OBJECT_INVALID;
string sTypeDest;
int FlagAttrib GetCampaignInt (sBDD,GetTag(oPorte)+"attrib");
if (
FlagAttrib == TRUE)
    {
    
string sTagDest GetCampaignString (sBDD,GetTag(oPorte)+"dest");
    
oDest GetObjectByTag (sTagDest);
    }
else
    {
    if (
GetTypePorte(oPorte) == "ET"sTypeDest "RC";
    if (
GetTypePorte(oPorte) == "RC"sTypeDest "ET";
    
string sTagBase GetTagBase (oPorte) + sTypeDest;
    
int iNbrPrt GetLocalInt (GetModule(), sTagBase +"nb");
    if (
iNbrPrt == 0)  
        {
        
CalculPorte (sTagBase);
        
iNbrPrt GetLocalInt (GetModule(), sTagBase +"nb");
        }
    
FlagAttrib FALSE
    
int FlagDest;
    
int tNb 0;
    
int iRand Random (iNbrPrt) +1;
    while ((
tNb <= iNbrPrt)&&(FlagAttrib == FALSE))
        {
        
tNb ++;
        
oDest GetObjectByTag (sTagBase ComptToString (GetBoucle (tNbiRandiNbrPrt)));
        
FlagDest GetCampaignInt (sBDD,GetTag(oDest)+"attrib");
        if ((
FlagDest == FALSE)&&(oDest!= OBJECT_INVALID))
            {
            
SetCampaignInt (sBDD,GetTag(oDest)+"attrib",TRUE);
            
SetCampaignInt (sBDD,GetTag(oPorte)+"attrib",TRUE);
            
SetCampaignString (sBDD,GetTag(oDest)+"dest",GetTag(oPorte));
            
SetCampaignString (sBDD,GetTag(oPorte)+"dest",GetTag(oDest));
            
FlagAttrib TRUE;
            }
       }
      }
return 
oDest;  

et enfin le script à metre sur les event OnClick

Code PHP:

#include "ktx_portealeat_include" // remplacer par le nom du script de bibliothèque

void main ()
{
object oPCclk GetClickingObject();
string sTag GetTag(OBJECT_SELF);
object oDestination SetDestination (OBJECT_SELF);
AssignCommand (oDestinationActionOpenDoor(oDestination));
AssignCommand (oPCclkClearAllActions ());
location lRandomLocation KTXGetBehindDoor(oDestination);
DelayCommand (1.0AssignCommand (oPCclkJumpToLocation (lRandomLocation)));
// j'ai mis un delay d'une seconde mais on peut l'enlever

__________________
http://img91.imageshack.us/img91/9666/yingyangwm8jt3.gif
http://simaon.free.fr/
Excellent ca !

C est marrant parce que de mon coté j ai bossé sur un systeme de generation de tresor aleatoire/generation de level des monstre aleatoire/ et generation aleatoire d objets magiques sur les mobs.

C est pas finalisé, mais ca marche pas trop mal. Si tu veux je pourrai mettre mes scripts ici et libre a qui veux de les modifier


Pour le facing, je vois pas de trop.....
N'hésite pas à les mettre en ligne.

Pour les autres qui hésitent, je sais que c'est difficile de travailler des heures tout seul dans son coin pour faire quelque chose et de le "donner" aux autres mais au final ce n'est pas ceci qui fait la qualité du module, mais l'ensemble.

Un module peut avoir des supers maps, des supers scripts, des supers dialogues, mais si l'ensemble du module est incohérent, il ne sera jamais bien
__________________
http://img91.imageshack.us/img91/9666/yingyangwm8jt3.gif
http://simaon.free.fr/
SetFacing() pour le joueur non ?

Le système est intéressant en tout cas. Ce qui m'étonne un peu, c'est que les portes d'une zone sont définies comme étant soit "entrée", soit "sortie". Pourquoi pas les deux en même temps ?

Et est-ce possible de faire des zones avec plusieurs portes ?

Bravo sinon
"SetFacingPoint()" n'est pas mal non plus, ça peut éviter de se taper des calculs soi-même.

Genre un repère au milieu de la pièce, un "SetFacingPoint()" pointant vers ce repère, et paf.
Code PHP:

vector vPosition GetPosition(oRepère);
AssignCommand(oTruc,SetFacingPoint(vPosition)); 
Citation :
Publié par Ghazghkull
Tes portes mènent vers une autre porte ou vers un point de passage ?
Les portes ont dans leur propriétés soit "transition vers une portes" soit "transition vers un point de passage", et ceci pour activer l'event OnClick quand la porte est ouverte. Mais au final elles n'ont aucune cible.. C'est le script qui leur assigne une cible (une porte ou une zone de transition selon les tag)

On peut mettre d'autres placeables aussi, c'est leur tag qui compte et le script mis sur le OnClick


Citation :
Publié par Taern
SetFacing() pour le joueur non ?

Le système est intéressant en tout cas. Ce qui m'étonne un peu, c'est que les portes d'une zone sont définies comme étant soit "entrée", soit "sortie". Pourquoi pas les deux en même temps ?

Et est-ce possible de faire des zones avec plusieurs portes ?

Bravo sinon
Oui bien sûr on peut mettre plusieurs entrée et/ou sorties
Quand un joueur se fait téléporté par une porte X vers une porte Y, le script enregistre la liaison de la porte X vers Y mais aussi de Y vers X

Plusieurs entrées, c'est quand même "risqué" car les maisons pourrait avoir des incohérences géographiques : il faut, pour que le donjon se construise, que les joueurs le fassent dans un sens n => n+1

Ze pourquoi : avec plusieurs entrées, 2 zones séparées "géographiquement" de quelques autres "zones" (c'est pas forcément un zone au sens de l'éditeur ) pourraient se retrouver liée par une porte. par contre s'il y a plusieurs sorties, les joueurs se déplaceront dans des "zones" qui n'auront pas été choisies
L'essentiel c'est de doser le nombre de portes d'entrées et de sorties de "zones"

S'il y a plus de portes de sorties que de portes d'entrée, certaines de ces portes seront inutilisables
S'il y a plus de portes d'entrée que de sorties, certaines portes d'entrées seront inutilisées et donc certaines "zones" aussi)



NOTE IMPORTANTE : Juste une précision que j'avais omise : il faut effacer la base de données qui sauvegarde la localisation des PJ en même temps que la base de données du donjon, sinon un PJ qui se retrouve DANS le donjon, s'il change, risque d'avoir 1 drôle de surprise




Pour ce qui est du SetFacing, il ne s'applique pas par avance, donc il faut utiliser un DelayCommand correspondant au temps de téléportation vers la nouvelle zone. On peut très bien l'appliquer en direct avec une ligne du genre
Code PHP:

AssignCommand(oJoueurSetFacing (oJoueurGetFacing (oJoueur)+180.0f)); 

mais si on change de zone il faut prévoir le temps de chargement.. Ca se fait en direct cette commande

par conre je comprends pas dans une location, la direction y est et je n'arrive pas à la changer (3eme argument... location (area, vector, direction) )
Bref c'est à voir, j'ai peut être déconné un peu aussi

Le plus important dans ce script c'est de savoir que la construction d'un donjon se fait dans un seul sens et ressemblants aux branches d'un arbre
__________________
http://img91.imageshack.us/img91/9666/yingyangwm8jt3.gif
http://simaon.free.fr/
Plutôt qu'un simple "AssignCommand()", étoffe le d'un "ActionDoCommand()", histoire de placer l'action en fin de file d'attente du joueur :
Code PHP:

AssignCommand(oJoueur,ClearAllActions(TRUE));
 
AssignCommand(oJoueur,ActionJumpToLocation(lLocation));
 
AssignCommand(oJoueur,ActionDoCommand(SetFacing(oJoueur,GetFacing(oJoueur)+180))); 
A partir du "ClearAllActions(TRUE)", on est certain que la file d'attente est entièrement vide. Le joueur se téléportera en premier, puis dès que le processus de téléportation sera fini, il engagera le processus de changement d'orientation.

Sinon, mène-les systématiquement vers un WayPoint orienté de la manière que tu souhaites. Ce qui te permettra de leur donner directement une zone, une position, et une orientation, sans avoir besoin de procéder à une série de calculs.


Pour changer l'orientation d'une localisation, il faut au préalable la dépiauter :
Code PHP:

// Modification de l'orientation dans une localisation :
 
location SetFacingToLocation(location lLocationfloat fModifier=0.0)
 {
     
object oArea GetAreaFromLocation(lLocation);
     
vector vPosition GetPositionFromLocation(lLocation);
     
float fFacing GetFacingFromLocation(lLocation)+fModifier;

     return 
Location(oArea,vPosition,fFacing);
 }

// Modification d'une position dans une localisation :
 
location SetPositionToLocation(location lLocationfloat fModifierX=0.0float fModifierY=0.0float fModifierZ=0.0)
 {
     
object oArea GetAreaFromLocation(lLocation);
     
vector vPosition GetPositionFromLocation(lLocation);
     
vNewPosition Vector(vPosition.x+fX,vPosition.y+fY,vPosition.z+fZ);
     
float fFacing GetFacingFromLocation(lLocation);

     return 
Location(oArea,vNewPosition,fFacing);
 } 
petite mise à jour optionnelle du script, ou plus précisément de la fonction SetDestination afin d'intégrer des construction plus complexes de donjon ou de maisons (pour ce qui veulent).

le donjon sera bien plus compliqué à faire, il faudra bien être concentré sur la création des portes. En effet, il intègre les sous sols, les rez de chaussés et les étages, avec différents types de portes.

- Toutes les portes extérieures aux zones aléatoires auront pour type "EX", et auront pour cible des portes de type rez de chaussé ("RC")
- Les portes qui mèneront aux étages "MO" auront pour type et mènent à des portes étages "ET"
- Les portes qui mèneront aux sous sols "CA" (pour cave) auront pour type et mènent à des portes étages "SS"

Cette création oblige pas mal de précision mais permet de faire des donjons autres que toujours monter ou toujours descende


EXEMPLE

(## remplace des chiffres 01, 02, 03, 04...)

Zone ---------------tag de la porte --- Destination

Zone extérieur ----------------- TagPorteEX## ---------- TagPorteRC##

Rez de Chaussé (3 portes) -- TagPorteRC## ---------- TagPorteRC##
---------- (+ porte d'entrée) -- TagPorteCA## ---------- TagPorteSS##
------------------------------------ TagPorteMO## ---------- TagPorteET##

Etage 1 (2 portes) ------------ TagPorteMO## ---------- TagPorteET##
(+ porte d'entrée) ------------ TagPorteMO## ---------- TagPorteET##





Code PHP:

object SetDestination (object oPorte)
{
object oDest OBJECT_INVALID;
string sTypeDest;
int FlagAttrib GetCampaignInt (sBDD,GetTag(oPorte)+"attrib");
if (
FlagAttrib == TRUE)
    {
    
string sTagDest GetCampaignString (sBDD,GetTag(oPorte)+"dest");
    
oDest GetObjectByTag (sTagDest);
    }
else
    {
    if (
GetTypePorte(oPorte) == "CA"sTypeDest "SS";
    if (
GetTypePorte(oPorte) == "MO"sTypeDest "ET";
    if (
GetTypePorte(oPorte) == "EX"sTypeDest "RC";
    if (
GetTypePorte(oPorte) == "RC"sTypeDest "RC";
    
string sTagBase GetTagBase (oPorte) + sTypeDest;
    
int iNbrPrt GetLocalInt (GetModule(), sTagBase +"nb");
    if (
iNbrPrt == 0)  
        {
        
CalculPorte (sTagBase);
        
iNbrPrt GetLocalInt (GetModule(), sTagBase +"nb");
        }
    
FlagAttrib FALSE
    
int FlagDest;
    
int tNb 0;
    
int iRand Random (iNbrPrt) +1;
    while ((
tNb <= iNbrPrt)&&(FlagAttrib == FALSE))
        {
        
tNb ++;
        
oDest GetObjectByTag (sTagBase ComptToString (GetBoucle (tNbiRandiNbrPrt)));
        
FlagDest GetCampaignInt (sBDD,GetTag(oDest)+"attrib");
        if ((
FlagDest == FALSE)&&(oDest!= OBJECT_INVALID))
            {
            
SetCampaignInt (sBDD,GetTag(oDest)+"attrib",TRUE);
            
SetCampaignInt (sBDD,GetTag(oPorte)+"attrib",TRUE);
            
SetCampaignString (sBDD,GetTag(oDest)+"dest",GetTag(oPorte));
            
SetCampaignString (sBDD,GetTag(oPorte)+"dest",GetTag(oDest));
            
FlagAttrib TRUE;
            }
       }
      }
return 
oDest;  


Pour ma part je ne pense pas l'utiliser, car les zones deviennent monstrueuses à créer et pour les maisons, il suffit de ne pas faire de caves ou d'étages selon le cas, mais ça peut intéresser ceux qui veulent faire un système parfait
__________________
http://img91.imageshack.us/img91/9666/yingyangwm8jt3.gif
http://simaon.free.fr/
Citation :
Publié par KorTeX
EXEMPLE

(## remplace des chiffres 01, 02, 03, 04...)

Zone tag de la porte Destination

Zone extérieur ----------------- TagPorteEX## ---------- TagPorteRC##

Rez de Chaussé (3 portes) -- TagPorteRC## ---------- TagPorteEX##
---------- (+ porte d'entrée) -- TagPorteCA## ---------- TagPorteSS##
------------------------------------ TagPorteMO## ---------- TagPorteET##

Etage 1 (2 portes) ------------ TagPorteMO## ---------- TagPorteET##
(+ porte d'entrée) ------------ TagPorteMO## ---------- TagPorteET##

Les portes de tag "TagPorteRC" mène bien aux portes des tag "TagPorteEX" ? Tu avais mis qu'elles menaient aux portes de tag "TagPorteRC"...
non une porte RC mène bien à une porte RC (afin de faire des niveaux plats... euh sans niveau)
La construction du donjon / de la maison se fait dans un sens, donc la porte EX mènera à une première porte RC, les 2 étant reliées entre elles, mais ensuite les portes RC mèneront à une autre porte RC




t'as essayé de me piéger vil et mesquin adpepte de Torm... depuis le temps tu n'as pas appris ??
__________________
http://img91.imageshack.us/img91/9666/yingyangwm8jt3.gif
http://simaon.free.fr/
bon suite aux tests effectués, je vais faire un SAV

il se peut que les transferts ne fonctionnent pas. Dans ce cas il faut vérifier :
- les tags des portes. très importants d'ailleurs. La casse doit être respectée ("TagdePorte" est différent de "TagDePorte" par exemple)
- Etre sûr que chaque porte aléatoire ait un tag unique
- Vérifier que la porte ne soit pas dans une zone inaccessible (problème de walkmesh) : en effet, c'est ce point qui m'a posé le plus de problème. La location choisie se trouve juste devant la porte, et certains bâtiments (comme les bâtiments de la rue des docks par exemple) ont une collision qui dépasse de beaucoup de bâtiment en lui même. Donc quelque soit le mode de calcul de la location de destination, la première location (prise en fonction de la porte de destination) est invalide du coup il faut pour cela rendre le bâtiment accessible (soit en mettant accessible sur TRUE, soit en le mettant en tant qu'élément d'environnement) et rogner le walkmesh ensuite, en laissant la possibilité de rentrer dans le bâtiment (la porte bloquera cette entrée donc pas de soucis de ce côté là )

voilà j'espère avoir été clair dans mes explications ..
(je vais vous faire un dessin afin de vous montrer mes talents de dessinateurs )

http://img118.imageshack.us/img118/4401/albddgy3.jpg
Répondre

Connectés sur ce fil

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