describe.c (8929B)
1 2 #include "describe.h" 3 #include <assert.h> 4 #include <stdio.h> 5 #include <ctype.h> 6 #include <string.h> 7 8 #define ADJ_PUSHED 1 9 #define ADJ_NOT_PUSHED 2 10 11 /* various functions used to describe the scene */ 12 13 static int push_sized_word(struct cursor *strs, const char *str, int len) 14 { 15 if (strs->p-1 >= strs->start && !isspace(*(strs->p-1))) { 16 if (!cursor_push_str(strs, " ")) 17 return 0; 18 } 19 20 if (!push_sized_str(strs, str, len)) 21 return 0; 22 23 return 1; 24 } 25 26 static int push_word(struct cursor *strs, const char *str) 27 { 28 return push_sized_word(strs, str, strlen(str)); 29 } 30 31 static int push_adjective(struct cursor *strs, struct attribute *attr) 32 { 33 int ok; 34 35 switch (attr->type) { 36 case A_COLOR: 37 case A_CONDITION: 38 ok = cursor_push_str(strs, " "); 39 if (!ok) return 0; 40 ok = push_sized_str(strs, attr->data.str.ptr, 41 attr->data.str.len); 42 if (!ok) return 0; 43 return ADJ_PUSHED; 44 default: 45 break; 46 } 47 48 return ADJ_NOT_PUSHED; 49 } 50 51 static int is_adjective(struct attribute *attr) 52 { 53 return attr->type == A_CONDITION || attr->type == A_COLOR; 54 } 55 56 static int count_adjectives(struct describe *desc) 57 { 58 struct attribute *attr; 59 int count; 60 int i; 61 62 for (i = 0, count = 0; i < desc->cell->n_attributes; i++) { 63 attr = get_attr(&desc->parsed->attributes, 64 desc->cell->attributes[i]); 65 assert(attr); 66 67 if (is_adjective(attr)) 68 count++; 69 } 70 71 return count; 72 } 73 74 static int push_adjectives(struct describe *desc) 75 { 76 struct attribute *attr; 77 int i, ok, adjs, adj_count; 78 79 adj_count = count_adjectives(desc); 80 81 for (i = 0, adjs = 0; i < desc->cell->n_attributes; i++) { 82 attr = get_attr(&desc->parsed->attributes, 83 desc->cell->attributes[i]); 84 assert(attr); 85 86 if (!is_adjective(attr)) 87 continue; 88 89 if (adjs > 0) { 90 if (adjs == adj_count-1) { 91 ok = push_word(desc->strs, "and"); 92 if (!ok) return 0; 93 } 94 else if (adjs != adj_count-1) { 95 ok = cursor_push_str(desc->strs, ","); 96 if (!ok) return 0; 97 } 98 99 } 100 101 ok = push_adjective(desc->strs, attr); 102 if (ok == ADJ_PUSHED) 103 adjs++; 104 } 105 106 return 1; 107 } 108 109 static int find_attr(struct cursor *attrs, struct cell *cell, 110 enum attribute_type type, struct attribute **attr) 111 { 112 int i; 113 114 for (i = 0; i < cell->n_attributes; i++) { 115 *attr = get_attr(attrs, cell->attributes[i]); 116 assert(*attr); 117 118 if ((*attr)->type == type) 119 return 1; 120 } 121 122 return 0; 123 } 124 125 static int push_made_of(struct describe *desc) 126 { 127 struct attribute *attr; 128 int ok; 129 130 ok = find_attr(&desc->parsed->attributes, desc->cell, 131 A_MATERIAL, &attr); 132 if (!ok) return 2; 133 134 ok = push_word(desc->strs, "made of"); 135 if (!ok) return 0; 136 137 ok = push_sized_word(desc->strs, attr->data.str.ptr, 138 attr->data.str.len); 139 if (!ok) return 0; 140 return 1; 141 } 142 143 static int push_named(struct describe *desc) 144 { 145 const char *name; 146 int name_len; 147 int ok; 148 149 cell_attr_str(&desc->parsed->attributes, desc->cell, &name, &name_len, 150 A_NAME); 151 152 if (name_len == 0) 153 return 1; 154 155 ok = push_word(desc->strs, "named"); 156 if (!ok) return 0; 157 158 ok = push_sized_word(desc->strs, name, name_len); 159 if (!ok) return 0; 160 161 return 1; 162 } 163 164 static int push_shape(struct describe *desc) 165 { 166 struct attribute *attr; 167 int ok; 168 169 ok = find_attr(&desc->parsed->attributes, desc->cell, A_SHAPE, &attr); 170 if (!ok) return 2; 171 172 switch (attr->data.shape) { 173 case SHAPE_RECTANGLE: 174 push_word(desc->strs, "rectangular"); 175 break; 176 case SHAPE_CIRCLE: 177 push_word(desc->strs, "circular"); 178 break; 179 case SHAPE_SQUARE: 180 push_word(desc->strs, "square"); 181 break; 182 } 183 184 return 1; 185 } 186 187 static int describe_detail(struct describe *desc, const char *name) 188 { 189 int ok; 190 191 /* TODO: temp buffers for determining a(n) things */ 192 ok = cursor_push_str(desc->strs, "There is a(n)"); 193 if (!ok) return 0; 194 195 ok = push_adjectives(desc); 196 if (!ok) return 0; 197 198 ok = push_shape(desc); 199 if (!ok) return 0; 200 201 ok = push_word(desc->strs, name); 202 if (!ok) return 0; 203 204 ok = push_made_of(desc); 205 if (!ok) return 0; 206 207 ok = push_named(desc); 208 if (!ok) return 0; 209 210 return 1; 211 } 212 213 static int describe_amount(struct describe *desc, int nobjs) 214 { 215 int ok; 216 217 if (nobjs == 1) { 218 ok = push_word(desc->strs, "a single"); 219 if (!ok) return 0; 220 } else if (nobjs == 2) { 221 ok = push_word(desc->strs, "a couple of"); 222 if (!ok) return 0; 223 } else if (nobjs == 3) { 224 ok = push_word(desc->strs, "three"); 225 if (!ok) return 0; 226 } else if (nobjs == 4) { 227 ok = push_word(desc->strs, "four"); 228 if (!ok) return 0; 229 } else if (nobjs == 5) { 230 ok = push_word(desc->strs, "five"); 231 if (!ok) return 0; 232 } else { 233 ok = push_word(desc->strs, "many"); 234 if (!ok) return 0; 235 } 236 237 return 1; 238 } 239 240 static int describe_object_name(struct cursor *strs, 241 struct cursor *attrs, struct cell *cell) 242 { 243 const char *name; 244 int name_len; 245 246 cell_attr_str(attrs, cell, &name, &name_len, A_NAME); 247 if (name_len > 0 && !push_sized_word(strs, name, name_len)) 248 return 0; 249 250 if (cell->type == C_OBJECT) { 251 if (cell->obj_type == O_OBJECT) 252 return 1; 253 return push_word(strs, object_type_str(cell->obj_type)); 254 } 255 256 return push_word(strs, cell_type_str(cell->type)); 257 } 258 259 static int describe_group_children(struct cell *parent, struct describe *desc) 260 { 261 int i; 262 struct cell *child; 263 264 if (!push_word(desc->strs, "a")) 265 return 0; 266 267 for (i = 0; i < parent->n_children; i++) { 268 child = get_cell(&desc->parsed->cells, parent->children[i]); 269 assert(child); 270 271 if (i > 0) { 272 if (i == parent->n_children-1) { 273 if (!push_word(desc->strs, "and")) 274 return 0; 275 } 276 else if (i != parent->n_children-1) { 277 if (!cursor_push_str(desc->strs, ",")) 278 return 0; 279 } 280 281 } 282 283 if (!describe_object_name(desc->strs, &desc->parsed->attributes, child)) 284 return 0; 285 } 286 287 return 1; 288 } 289 290 static int describe_group(struct describe *desc) 291 { 292 if (!describe_amount(desc, desc->cell->n_children)) 293 return 0; 294 295 if (!push_word(desc->strs, "object")) 296 return 0; 297 298 if (desc->cell->n_children > 1) { 299 if (!cursor_push_str(desc->strs, "s:")) 300 return 0; 301 } 302 else { 303 if (!cursor_push_str(desc->strs, ":")) 304 return 0; 305 } 306 307 return describe_group_children(desc->cell, desc); 308 } 309 310 static int describe_object(struct describe *desc) 311 { 312 return describe_object_name(desc->strs, &desc->parsed->attributes, 313 desc->cell); 314 } 315 316 static int describe_object_detailed(struct describe *desc) 317 { 318 if (!cursor_push_byte(desc->strs, 'A')) 319 return 0; 320 321 if (!push_adjectives(desc)) 322 return 0; 323 324 if (!push_shape(desc)) 325 return 0; 326 327 if (!describe_object_name(desc->strs, &desc->parsed->attributes, desc->cell)) 328 return 0; 329 330 if (!push_made_of(desc)) 331 return 0; 332 333 return 1; 334 } 335 336 int describe_cell(struct describe *desc) 337 { 338 switch (desc->cell->type) { 339 case C_ROOM: 340 return describe_detail(desc, "room"); 341 case C_SPACE: 342 return describe_detail(desc, "space"); 343 case C_GROUP: 344 return describe_group(desc); 345 case C_OBJECT: 346 return describe_object(desc); 347 } 348 349 return 1; 350 } 351 352 static int describe_cell_detailed(struct describe *desc) 353 { 354 switch (desc->cell->type) { 355 case C_ROOM: 356 case C_SPACE: 357 case C_GROUP: 358 return describe_cell(desc); 359 case C_OBJECT: 360 return describe_object_detailed(desc); 361 } 362 363 return 0; 364 } 365 366 367 static int describe_cell_name(struct describe *desc) 368 { 369 if (desc->cell->type == C_OBJECT) 370 return describe_object(desc); 371 372 return push_word(desc->strs, cell_type_str(desc->cell->type)); 373 } 374 375 static int describe_cell_children(struct describe *desc); 376 377 static int describe_cell_children_rest(struct describe desc) 378 { 379 int i; 380 struct cell *parent = desc.cell; 381 382 for (i = 0; i < parent->n_children; i++) { 383 desc.cell = get_cell(&desc.parsed->cells, parent->children[i]); 384 385 if (desc.cell->n_children > 0 && !describe_cell_children(&desc)) 386 return 0; 387 } 388 389 return 1; 390 } 391 392 static int describe_cell_children_group(struct describe desc) 393 { 394 struct cell *child; 395 396 if (desc.cell->n_children == 1 && 397 (child = get_cell(&desc.parsed->cells, desc.cell->children[0])) && 398 child->type == C_GROUP) { 399 desc.cell = child; 400 return describe_cell_children_group(desc); 401 } 402 403 if (!describe_group_children(desc.cell, &desc)) 404 return 0; 405 406 if (!cursor_push_byte(desc.strs, '\n')) 407 return 0; 408 409 return describe_cell_children_rest(desc); 410 } 411 412 static int describe_cell_children(struct describe *desc) 413 { 414 if (!push_word(desc->strs, "The")) 415 return 0; 416 417 if (!describe_cell_name(desc)) 418 return 0; 419 420 if (!push_word(desc->strs, "contains")) 421 return 0; 422 423 return describe_cell_children_group(*desc); 424 } 425 426 int describe_cells(struct describe *desc) 427 { 428 if (!describe_cell_detailed(desc)) 429 return 0; 430 431 if (!cursor_push_str(desc->strs, ".\n")) 432 return 0; 433 434 if (desc->cell->n_children == 0) 435 return 1; 436 437 return describe_cell_children(desc); 438 } 439 440 441 int describe(struct parser *parser, u16 root_cell) 442 { 443 static char strbuf[4096*32]; 444 struct cursor strs; 445 struct cell *cell; 446 struct describe desc; 447 448 strbuf[0] = 0; 449 450 cell = get_cell(&parser->cells, root_cell); 451 452 make_cursor((u8*)strbuf, (u8*)strbuf + sizeof(strbuf), &strs); 453 454 desc.cell = cell; 455 desc.parsed = parser; 456 desc.strs = &strs; 457 458 describe_cells(&desc); 459 460 printf("\n\ndescription\n-----------\n\n%s\n", strbuf); 461 462 return 1; 463 }