Retour aux fichiers de configuration d'un niveau/ville/monde
Comme tout projet qui se crée sans documentation ou cahier de charge digne de ce nom, il y a des changements internes qui arrivent ici et là. Entre mes idées de départ et ce vers quoi nous tendons en ce moment, il y a des petites différences qui sont importantes à noter.
1) Pourquoi ces changements ?
La plupart des changements proviennent de deux horizons : la mise en place des sauvegardes cet été et l'ajout de fonctionallités.
2) Qu'est-ce qui a changé ?
Revenons à la première version :
- Un fichier graphique avec des couleurs donnant : les murs, les sprites, les teleportations mais aussi les personnages
- Un fichier de configuration qui est lié et explique les correspondances couleurs
Ceci était problématique :
- Déjà, pour la sauvegarde, cela veut dire que le programme doit regénérer un fichier image lorsque le monde change. En soit, ce n'est pas difficile mais cela veut dire que la sauvegarde doit contenir toutes les images des niveaux différents. Et moi, je trouve cela un peu gros...
- Ensuite, un souci est survenu lorsque je voulais avoir plusieurs choses sur une case : une épée et une armure sur le sol; un corps et un garde, etc.
Tout devint un peu bancal et du coup, un nettoyage se produit !
- Solution au problème :
1) Le fichier image existe toujours mais maintenant ne montre que les sprites de fond. On a sorti les personnages, les teleporteurs et tout le reste.
2) Le fichier de configuration contient toutes ces informations:
Tout d'abord, nous avons les mêmes informations qu'avant :
1 2 3 4 5 6 7 8 9
|
#Image of the city
novea.bmp
#Default sprite sheet
sprites.bmp
#Size of one tile
16 16
#Size of image
32 64 |
Rien de particulier ici, on lie la ville à son image, on donne l'image des sprites et les tailles respectives des tuiles et de l'image.
Nouveauté (rien à voir avec ce post vraiment mais présent):
1 2 3
|
#Maximum number of monsters in map
0 |
On a un nombre maximum de monstres qui seront générés automatiquement dans la carte (si la valeur est != 0, on met le pourcentage de création d'un monstre).
Ensuite, nous avons les correspondances des tuiles :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
#Each convention is defined by:
# - The color (B,G,R)
# - Type of convention
# - Not animated (background image) 0
# - Animated background 1
# - The passage cost (0 for not allowed) (if animated or not)
# - Is transparent for visibility or not
# - Is it a light source (force of light source)
# - Is it a counter (should talking go over or not)
25
Grass 0 0 0 0 5 1 1 1 0 0
Water 0 0 128 1 water_shallow.txt 0 1 0 0
P 0 20 50 0 15 22 0 1 0 1
A 0 20 200 0 0 22 0 1 0 1
E 0 20 255 0 4 22 0 1 0 1
W 0 60 255 0 6 23 0 1 0 1
I 0 63 0 0 8 22 0 1 0 1
F 0 64 0 0 5 22 0 1 0 1
M 0 100 255 0 12 22 0 1 0 1
Tree 0 128 0 0 14 3 2 1 0 0
Bridge 0 128 255 0 11 35 1 1 0 0
Grass 0 170 0 0 6 1 1 1 0 0
R 0 200 255 0 1 23 0 1 0 1
Bridge 0 255 0 0 6 0 1 1 0 0
O 0 255 255 0 14 22 0 1 0 1
N 20 100 0 0 13 22 0 1 0 1
T 50 50 50 0 3 23 0 1 0 1
L 100 100 100 0 11 22 0 1 0 1
D 128 0 0 0 3 22 0 1 0 1
Window 200 0 200 0 10 5 0 1 0 0
Wall 255 0 255 0 15 5 0 0 0 0
U 255 50 255 0 4 23 0 1 0 1
Counter 255 255 0 0 10 23 0 1 0 1
Lamppost 255 255 255 1 lamppost.txt 0 1 6 0
Staircase 64 64 64 0 4 13 1 0 0 0 |
Rien de nouveau sauf le nom de la tuile (sert à faire un "Look").
Remarquez bien la disparition des NPCs et de tout autre type.
Ensuite, nous avons les NPCs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
#Now NPCs
11
28 16 potionSeller.txt
35 18 toolSeller.txt
48 20 foodSeller.txt
51 24 katrina_npc.txt
8 28 guard.txt
8 31 guard.txt
20 30 follower.txt
25 38 armorSeller.txt
54 41 guard.txt
23 46 weaponSeller.txt
45 57 truelle.txt |
On donne la position de départ et son fichier de configuration.
Ensuite, on a la définition des teleportations :
1 2 3 4 5 6 7
|
#Teleports
4
World 0 163 212 world.txt 1 0 0
Isle 1 48 6110 0 0
Mainland 1 54 1910 0 0
Upstairs 0 7 28 novea_up.txt 0 0 1 |
On a aussi un nom pour la teleportation, ensuite les champs sont :
- Est-ce que c'est local (dans la même carte ou non) ?
- Destination (x,y) de la teleportation
- Nom de la carte si non local
- Est-ce automatique ? (Lorsqu'on arrive sur la case, bim, on est teleporté ?)
- Est-ce qu'il faudrait entrer dedans ? (pour des villes par exemple)
- Est-ce qu'il faut descendre/monter ? (pour des escaliers)
Pour ces deux dernier, je risque de changer cela en une lettre, genre :
e pour entrer
c pour monter/descendre
Mais je ne sais pas si je vais avoir des cas multiples sur la même case... A voir donc.
Enfin, nous avons la définition des cases spéciales : case de la map qui contient quelque chose (un teleporteur, un objet, etc.)
1 2 3 4 5 6
|
66 #Number of special cells
0 3
1
#Objects
0 |
Ici nous avons les coordonnées, ensuite l'indice du teleporteur (0 si aucun). Enfin si des objets sont présents sur la cellule.
Et si nous avons des objets :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
10 30
0
#Objects
4
1
Sword
1
Robe
1000
Gold
1
Chest
63 30
1 |
On a bien sûr combien d'objets d'un type nous avons.
Histoire de sourire : j'ai passé pas mal de temps à réfléchir à comment gérer un coffre. En principe, le coffre contient des affaires et nous pouvons y accéder en l'ouvrant.
Par contre, cela compliquait les choses et surtout ma sauvegarde. Du coup, j'ai triché un peu. Vu que nous pouvons simplement accéder à l'objet le plus haut, j'ai mis le coffre en dernier.
Ce qui veut dire : il faut l'ouvrir pour accéder aux affaires en dessous !
Comment cela fonctionne : lorsqu'on ouvre un coffre, l'objet coffre disparaît et on met un objet coffre ouvert au fond de la liste objets.
Le code qui fait cela se trouve ici :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
std::string Cell::openObject (void)
{
if (objects.size () > 0)
{
//Check if it's a chest
if (objects[objects.size () - 1].object->getName ().compare ("Chest") == 0)
{
unsigned int i = 0;
while (i < objects.size ())
{
if (objects[objects.size () - 1].object->getName ().compare ("Open Chest") != 0)
break;
i++;
}
//Move object index i to this one
objects[objects.size () - 1] = objects[i];
//Now put a open chest in position i
struct sHaveObject sho = {Object_Factory::getObject ("Open Chest"), 1};
objects[i] = sho;
return "Chest";
}
}
return "Nothing to open";
} |
Comme vous voyez, je triche encore plus. Vu que j'ai un vecteur, je cherche d'abord le premier objet qui n'est pas un coffre ouvert. Dès que je le trouve (cela peut être le coffre à la limite s'il est vide), je remplace la case coffre avec la case de l'objet.
Cela permet d'avoir une case vide pour le coffre ouvert !
Pour ceux qui ont suivi et se demande s'il n'y a pas de fuites sur ce code, considérez simplement la signature du vecteur :
std::vector <struct sHaveObject> objects; //Objects on the tile
Du coup, la sauvegarde est ultra simple à faire, nous pouvons simplement sauvegarder ce que nous devons (et plus les images).
Jc
Partager