annotate librpg/rpg/map-file.c @ 227:befa2e855d3b

core: reinterface the alloc module
author David Demelier <markand@malikania.fr>
date Thu, 19 Nov 2020 10:48:46 +0100
parents 64f24b482722
children 76afe639fd72
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
1 /*
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
2 * map-file.c -- map file loader
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
3 *
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
4 * Copyright (c) 2020 David Demelier <markand@malikania.fr>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
5 *
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
6 * Permission to use, copy, modify, and/or distribute this software for any
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
7 * purpose with or without fee is hereby granted, provided that the above
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
8 * copyright notice and this permission notice appear in all copies.
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
9 *
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
17 */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
18
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
19 #define _XOPEN_SOURCE 700
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
20 #include <assert.h>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
21 #include <errno.h>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
22 #include <libgen.h>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
23 #include <limits.h>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
24 #include <stddef.h>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
25 #include <stdio.h>
210
70e6ed74940d rpg: attempt of collide detection in map
David Demelier <markand@malikania.fr>
parents: 197
diff changeset
26 #include <stdlib.h>
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
27 #include <string.h>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
28
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
29 #include <core/alloc.h>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
30 #include <core/error.h>
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
31 #include <core/image.h>
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
32 #include <core/trace.h>
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
33
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
34 #include "map-file.h"
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
35
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
36 /* Create %<v>c string literal for scanf */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
37 #define MAX_F(v) MAX_F_(v)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
38 #define MAX_F_(v) "%" #v "c"
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
39
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
40 struct context {
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
41 struct map_file *mf; /* Map loader. */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
42 struct map *map; /* Map object to fill. */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
43 FILE *fp; /* Map file pointer. */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
44 char basedir[PATH_MAX]; /* Parent map directory */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
45 };
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
46
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
47 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
48 parse_layer_tiles(struct context *ctx, const char *layer_name)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
49 {
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
50 enum map_layer_type layer_type;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
51 size_t amount, current;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
52
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
53 if (strcmp(layer_name, "background") == 0)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
54 layer_type = MAP_LAYER_TYPE_BACKGROUND;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
55 else if (strcmp(layer_name, "foreground") == 0)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
56 layer_type = MAP_LAYER_TYPE_FOREGROUND;
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
57 else if (strcmp(layer_name, "above") == 0)
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
58 layer_type = MAP_LAYER_TYPE_ABOVE;
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
59 else
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
60 return errorf("invalid layer type: %s", layer_name);
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
61
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
62 amount = ctx->map->columns * ctx->map->rows;
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
63 current = 0;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
64
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
65 /*
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
66 * The next line after a layer declaration is a list of plain integer
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
67 * that fill the layer tiles.
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
68 */
227
befa2e855d3b core: reinterface the alloc module
David Demelier <markand@malikania.fr>
parents: 215
diff changeset
69 if (!(ctx->mf->layers[layer_type].tiles = alloc_array0(amount, sizeof (unsigned short))))
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
70 return false;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
71
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
72 for (int tile; fscanf(ctx->fp, "%d\n", &tile) && current < amount; ++current)
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
73 ctx->mf->layers[layer_type].tiles[current] = tile;
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
74
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
75 ctx->map->layers[layer_type].tiles = ctx->mf->layers[layer_type].tiles;
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
76
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
77 return true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
78 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
79
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
80 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
81 parse_actions(struct context *ctx)
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
82 {
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
83 char exec[128 + 1];
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
84 int x = 0, y = 0;
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
85 unsigned int w = 0, h = 0;
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
86
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
87 while (fscanf(ctx->fp, "%d|%d|%u|%u|%128[^\n]\n", &x, &y, &w, &h, exec) == 5) {
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
88 struct action *act;
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
89
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
90 if (!ctx->mf->load_action) {
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
91 tracef("ignoring action %d,%d,%u,%u,%s", x, y, w, h, exec);
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
92 continue;
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
93 }
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
94
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
95 if ((act = ctx->mf->load_action(ctx->map, x, y, w, h, exec)))
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
96 action_stack_add(&ctx->map->actions, act);
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
97 }
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
98
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
99 return true;
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
100 }
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
101
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
102 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
103 parse_layer(struct context *ctx, const char *line)
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
104 {
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
105 char layer_name[32 + 1] = {0};
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
106
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
107 /* Check if weight/height has been specified. */
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
108 if (ctx->map->columns == 0 || ctx->map->rows == 0)
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
109 return errorf("missing map dimensions before layer");
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
110
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
111 /* Determine layer type. */
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
112 if (sscanf(line, "layer|%32s", layer_name) <= 0)
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
113 return errorf("missing layer type definition");
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
114
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
115 if (strcmp(layer_name, "actions") == 0)
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
116 return parse_actions(ctx);
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
117
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
118 return parse_layer_tiles(ctx, layer_name);
212
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
119 }
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
120
ddfe0a211169 rpg: experiment with map teleport
David Demelier <markand@malikania.fr>
parents: 211
diff changeset
121 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
122 parse_tileset(struct context *ctx, const char *line)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
123 {
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
124 char path[PATH_MAX] = {0}, *p;
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
125 struct map_file *mf = ctx->mf;
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
126 struct tileset_file *tf = &mf->tileset_file;
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
127
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
128 if (!(p = strchr(line, '|')))
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
129 return errorf("could not parse tileset");
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
130
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
131 snprintf(path, sizeof (path), "%s/%s", ctx->basedir, p + 1);
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
132
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
133 if (!tileset_file_open(tf, &mf->tileset, path))
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
134 return false;
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
135
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
136 ctx->map->tileset = &mf->tileset;
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
137
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
138 return true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
139 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
140
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
141 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
142 parse_title(struct context *ctx, const char *line)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
143 {
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
144 if (sscanf(line, "title|" MAX_F(MAP_FILE_TITLE_MAX), ctx->mf->title) != 1 || strlen(ctx->mf->title) == 0)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
145 return errorf("null map title");
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
146
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
147 ctx->map->title = ctx->mf->title;
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
148
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
149 return true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
150 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
151
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
152 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
153 parse_columns(struct context *ctx, const char *line)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
154 {
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
155 if (sscanf(line, "columns|%u", &ctx->map->columns) != 1 || ctx->map->columns == 0)
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
156 return errorf("null map columns");
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
157
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
158 return true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
159 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
160
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
161 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
162 parse_rows(struct context *ctx, const char *line)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
163 {
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
164 if (sscanf(line, "rows|%u", &ctx->map->rows) != 1 || ctx->map->rows == 0)
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
165 return errorf("null map rows");
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
166
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
167 return true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
168 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
169
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
170 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
171 parse_origin(struct context *ctx, const char *line)
210
70e6ed74940d rpg: attempt of collide detection in map
David Demelier <markand@malikania.fr>
parents: 197
diff changeset
172 {
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
173 if (sscanf(line, "origin|%d|%d", &ctx->map->player_x, &ctx->map->player_y) != 2)
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
174 return errorf("invalid origin");
210
70e6ed74940d rpg: attempt of collide detection in map
David Demelier <markand@malikania.fr>
parents: 197
diff changeset
175
70e6ed74940d rpg: attempt of collide detection in map
David Demelier <markand@malikania.fr>
parents: 197
diff changeset
176 return true;
70e6ed74940d rpg: attempt of collide detection in map
David Demelier <markand@malikania.fr>
parents: 197
diff changeset
177 }
70e6ed74940d rpg: attempt of collide detection in map
David Demelier <markand@malikania.fr>
parents: 197
diff changeset
178
70e6ed74940d rpg: attempt of collide detection in map
David Demelier <markand@malikania.fr>
parents: 197
diff changeset
179 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
180 parse_line(struct context *ctx, const char *line)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
181 {
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
182 static const struct {
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
183 const char *property;
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
184 bool (*read)(struct context *, const char *);
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
185 } props[] = {
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
186 { "title", parse_title },
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
187 { "columns", parse_columns },
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
188 { "rows", parse_rows },
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
189 { "tileset", parse_tileset },
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
190 { "origin", parse_origin },
210
70e6ed74940d rpg: attempt of collide detection in map
David Demelier <markand@malikania.fr>
parents: 197
diff changeset
191 { "layer", parse_layer },
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
192 };
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
193
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
194 for (size_t i = 0; i < NELEM(props); ++i)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
195 if (strncmp(line, props[i].property, strlen(props[i].property)) == 0)
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
196 return props[i].read(ctx, line);
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
198 return true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
199 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
200
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
201 static bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
202 parse(struct context *ctx, const char *path)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
203 {
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
204 char line[1024];
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
205 char basedir[PATH_MAX];
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
206
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
207 snprintf(basedir, sizeof (basedir), "%s", path);
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
208 snprintf(ctx->basedir, sizeof (ctx->basedir), "%s", dirname(basedir));
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
209
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
210 while (fgets(line, sizeof (line), ctx->fp)) {
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
211 /* Remove \n if any */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
212 line[strcspn(line, "\n")] = '\0';
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
213
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
214 if (!parse_line(ctx, line))
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
215 return false;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
216 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
217
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
218 return true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
219 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
220
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
221 static bool
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
222 check(struct map *map)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
223 {
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
224 /*
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
225 * Check that we have parsed every required components.
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
226 */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
227 if (!map->title)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
228 return errorf("missing title");
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
229
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
230 /*
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
231 * We don't need to check width/height because parsing layers and
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
232 * tilesets already check for their presence, so only check layers.
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
233 */
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
234 if (!map->layers[0].tiles)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
235 return errorf("missing background layer");
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
236 if (!map->layers[1].tiles)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
237 return errorf("missing foreground layer");
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
238 if (!tileset_ok(map->tileset))
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
239 return errorf("missing tileset");
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
240
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
241 return true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
242 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
243
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
244 bool
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
245 map_file_open(struct map_file *file, struct map *map, const char *path)
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
246 {
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
247 assert(file);
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
248 assert(path);
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
249 assert(map);
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
250
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
251 struct context ctx = {
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
252 .mf = file,
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
253 .map = map,
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
254 };
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
255 bool ret = true;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
256
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
257 memset(map, 0, sizeof (*map));
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
258
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
259 if (!(ctx.fp = fopen(path, "r")))
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
260 return errorf("%s", strerror(errno));
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
261
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
262 if (!(ret = parse(&ctx, path)) || !(ret = check(map))) {
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
263 map_finish(map);
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
264 map_file_finish(file);
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
265 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
266
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
267 fclose(ctx.fp);
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
268
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
269 return ret;
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
270 }
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
271
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
272 void
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
273 map_file_finish(struct map_file *file)
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
274 {
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
275 assert(file);
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
276
215
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
277 free(file->layers[0].tiles);
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
278 free(file->layers[1].tiles);
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
279 free(file->layers[2].tiles);
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
280
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
281 tileset_file_finish(&file->tileset_file);
64f24b482722 rpg: implement tilesets separately, closes #2515 @4h
David Demelier <markand@malikania.fr>
parents: 212
diff changeset
282
197
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
283 memset(file, 0, sizeof (*file));
852d0b7817ce rpg: map, extreme cleanup, closes #2508 @4h
David Demelier <markand@malikania.fr>
parents:
diff changeset
284 }