Add SDL2_mixer support.
[runemen.git] / src / runeconf.c
blobc038da26ab16861496aa1255e91071190aa44979
1 #include <stdio.h>
2 #include <SDL.h>
4 #include "libs/lazyass/lazyass.h"
5 #include "libs/libcsslike/cssdom.h"
7 #include "rune.h"
8 #include "runeconf.h"
9 #include "draw.h"
10 #include "visual.h"
11 #include "ai.h"
13 unit_p bunits[MAX_BUNITS];
14 house_p bhouses[MAX_BHOUSES];
16 Uint16 num_bunits;
17 Uint16 num_bhouses;
19 char pseudo_marker[80];
21 char unit_classes[MAX_BUNITS][128];
22 char house_classes[MAX_BHOUSES][128];
24 #define TL_OR_PIX(NAM, MULT) \
25 if (NAM ## U[0] == 't' && NAM ## U[1] == 0) NAM = NAM * MULT; \
26 else if (NAM ## U[0] != 'p' || NAM ## U[1] != 'x' || NAM ## U[2] != 0) { \
27 fprintf(stderr, "Unknown unit '%s', please use 't' or 'px'\n", NAM ## U); \
28 return -1; \
31 void wipe_animation(animation_t *anim) {
33 anim->num_axises = 0;
35 anim->plane.x = anim->plane.y = 0;
36 anim->plane.w = TILE_W;
37 anim->plane.h = TILE_H;
41 void compute_houses() {
43 int i;
45 for (i = 0; i < MAX_BHOUSES; i++) {
47 house_p *housep = &bhouses[i];
49 housep->w = housep->body.plane.w / TILE_W;
50 housep->h = housep->body.plane.h / TILE_H;
56 void compute_units() {
58 int i, j;
60 for (i = 0; i < num_bunits; i++) {
62 unit_p *unitp = &bunits[i];
64 unitp->w = unitp->body.plane.w / TILE_W;
65 unitp->h = unitp->body.plane.h / TILE_H;
67 /* Copy body to face, but replace "frame" ref with "faceframe" ref */
68 memcpy(&unitp->face, &unitp->body, sizeof(animation_t));
69 for (j = 0; j < MAX_AAXIS; j++) {
70 if (unitp->face.axis_modifier[j] == UAXIS_FRAME) {
71 unitp->face.axis_modifier[j] = UAXIS_FACEFRAME;
78 /** Sprites... **/
79 void rcfg_parse_frames(animation_t *anim, Uint8 anim_index, const char *value) {
80 char cut[1024];
81 int num_frames;
82 int frame;
83 char *next;
85 strncpy(cut, value, sizeof(cut) - 1);
87 num_frames = 0;
88 next = strtok(cut, ",");
89 while (next) {
90 frame = atoi(next);
91 //printf("Animation %d, frame %d --> %d\n", anim_index, nf, fr);
92 anim->frame[anim_index][num_frames] = frame;
93 next = strtok(NULL, ",");
94 num_frames++;
96 anim->num_frames[anim_index] = num_frames;
99 int rcfg_apply_animation(animation_t *anim, const char *name, const char *value) {
101 int err = 0;
103 #define _eq(STR) (!strcasecmp(name, STR))
104 #define _veq(STR) (!strcasecmp(value, STR))
105 #define _sveq(STR) (!strcasecmp(subvalue, STR))
107 if (_eq("image")) {
109 anim->image = ASS_LoadTexture(value, &white);
110 printf("Loading image: %s for someone...\n", value);
113 else
114 if (_eq("tile-size")) {
115 int a, b;
116 char aU[4], bU[4];
117 if (sscanf(value, "%d%s %d%s", &a, aU, &b, bU) == 4) {
118 TL_OR_PIX(a, TILE_W);
119 TL_OR_PIX(b, TILE_H);
120 } else printf("Tile size must in Nu Nu format (N=number, u=unit(px,t))\n");
121 anim->plane.w = a;
122 anim->plane.h = b;
123 //printf("Unit %d plane: %d, %d\n", id, unitp->plane.x, unitp->plane.y);
125 else
126 if (_eq("tile-plane")) {
127 int a, b, c, d;
128 char aU[4], bU[4], cU[4], dU[4];
129 //printf("Scanning '%s'\n", value);
130 if (sscanf(value, "%d%s %d%s %d%s %d%s", &a, aU, &b, bU, &c, cU, &d, dU) == 8) {
131 TL_OR_PIX(a, TILE_W);
132 TL_OR_PIX(b, TILE_H);
133 TL_OR_PIX(c, TILE_W);
134 TL_OR_PIX(d, TILE_H);
135 anim->plane.x = a;
136 anim->plane.y = b;
137 anim->plane.w = c;
138 anim->plane.h = d;
139 } else if (sscanf(value, "%d%s %d%s", &a, aU, &b, bU) == 4) {
140 TL_OR_PIX(a, TILE_W);
141 TL_OR_PIX(b, TILE_H);
142 c = 512;
143 d = 512;
144 anim->plane.x = a;
145 anim->plane.y = b;
146 } else { printf("Tile plane must in Nu Nu or Nu Nu Nu Nu format (N=number, u=unit(px,t))\n"); return -1; }
148 //printf("Unit %d plane: %d, %d\n", 0, anim->plane.x, anim->plane.y);
150 else
151 if (_eq("tile-axis")) {
152 int a, b, c, d;
153 char subvalue[12], aU[4], bU[4];//, cU[4], dU[4];
154 if (sscanf(value, "%s %d%s %d%s %d %d", subvalue, &a, aU, &b, bU, &c, &d) == 7) {
155 TL_OR_PIX(a, TILE_W);
156 TL_OR_PIX(b, TILE_H);
157 c = c * anim->plane.w;
158 d = d * anim->plane.h;
159 //TL_OR_PIX(c, anim->plane.w);
160 //TL_OR_PIX(d, anim->plane.h);
161 } else if (sscanf(value, "%s %d %d", subvalue, &c, &d) == 3) {
162 a = 0;
163 b = 0;
164 c = c * anim->plane.w;
165 d = d * anim->plane.h;
166 //TL_OR_PIX(c, anim->plane.w);
167 //TL_OR_PIX(d, anim->plane.h);
168 } else { printf("Tile axis must be in S D D or S Nu Nu D D format (D=number, N=number, u=unit(px,t), S=string)\n"); return -1;}
169 //printf("Receiving offset '%s' multX %d multY %d offX %d offY %d\n",subvalue, a,b, c,d);
171 Uint8 anim_name = 0xFF;
173 if (_sveq("num")) anim_name = UAXIS_TYPE;
174 else if (_sveq("frame")) anim_name = UAXIS_FRAME;
175 else if (_sveq("mode")) anim_name = UAXIS_MODE;
177 if (anim_name != 0xFF) {
178 SDL_Rect *taxis;
179 int axis_id = -1;
180 int i;
181 for (i = 0; i < anim->num_axises; i++) {
182 if (anim->axis_modifier[i] == anim_name) {
183 axis_id = i;
184 break;
187 if (axis_id == -1) {
188 axis_id = anim->num_axises++;
190 taxis = &anim->axis_offset[axis_id];
191 taxis->x = a;
192 taxis->y = b;
193 taxis->w = c;
194 taxis->h = d;
195 anim->axis_modifier[axis_id] = anim_name;
197 else { printf("Please supply hardcoded axis identifier (num, frame)\n"); }
199 else err = 1; /* Not an animation param */
201 return err;
202 #undef _sveq
203 #undef _veq
204 #undef _eq
207 /** Houses **/
208 int rcfg_house_count(dom_iter* this, void* ptr) {
210 int i;
211 for (i = 0; i < MAX_BHOUSES; i++) {
212 house_p *housep = &bhouses[i];
214 wipe_animation(&housep->body);
215 //wipe_animation(&housep->face);
217 housep->icon = i;
218 housep->body.image = ASS_LoadTexture("data/gfx/runelord.bmp", &white);
222 pseudo_marker[0] = 0;
224 return MAX_BHOUSES;
227 int rcfg_house_pick(dom_iter* this, void* ptr) {
229 house_p *housep = ptr;
231 if (ptr == bhouses) {
232 this->cursor = 0;
235 this->next = (housep+1);
236 this->parent = NULL;
237 this->kids = NULL;
239 if (this->cursor++ > num_bhouses) {
240 this->next = NULL;
243 return 0;
246 char* rcfg_house_test(void *ptr, const char *name) {
247 #define _eq(STR) (!strcasecmp(name, STR))
248 house_p *housep = (house_p *)ptr;
249 int num = (housep - bhouses);
251 if (_eq("type")) return "building";
253 if (_eq("num")) {
254 static char buf[12];
255 snprintf(buf, sizeof(buf), "%d", num);
256 return buf;
259 if (_eq("id")) {
260 return housep->id;
263 if (_eq("class")) {
264 return house_classes[num];
267 return "";
268 #undef _eq
272 int rcfg_house_apply(void *ptr, const char *name, const char *value) {
273 #define _eq(STR) (!strcasecmp(name, STR))
274 #define _veq(STR) (!strcasecmp(value, STR))
275 #define _sveq(STR) (!strcasecmp(subvalue, STR))
277 house_p *housep = ptr;
278 int num = (housep - bhouses);
280 //printf(" Applying value %s = %s for house %d %s (%s)\n", name, value, num, housep->title, housep->id);
282 if (_eq("id")) {
283 strncpy(housep->id, value, LEN_HOUSE_ID);
285 /* If we have a pseudo-mark, auto-apply it to this house's class */
286 if (pseudo_marker[0]) {
287 char *cc = house_classes[num];
288 strncat(cc, " ", sizeof(house_classes[0]));
289 strncat(cc, pseudo_marker, sizeof(house_classes[0]));
292 else
293 if (_eq("pseudo")) {
294 if (_veq("last")) {
295 num_bhouses = num + 1;
296 if (num_bhouses > MAX_BHOUSES) num_bhouses = MAX_HOUSES;
299 else
300 if (_eq("pseudo-mark")) {
301 strncpy(pseudo_marker, value, sizeof(pseudo_marker));
303 else
304 if (_eq("class")) {
305 char *cc = house_classes[num];
306 strncat(cc, " ", sizeof(house_classes[0]));
307 strncat(cc, value, sizeof(house_classes[0]));
309 else
310 if (_eq("title")) {
311 strncpy(housep->title, value, LEN_HOUSE_TITLE);
313 else
314 if (_eq("icon")) housep->icon = atoi(value);
315 else
316 if (_eq("gold")) housep->gold_cost = atoi(value);
317 else
318 if (!rcfg_apply_animation(&housep->body, name, value)) {
319 //ok
321 else
322 if (_eq("offset-unbuilt")) {
323 int a, b;
324 char aU[4], bU[4];
325 if (sscanf(value, "%d%s %d%s", &a, aU, &b, bU) == 4) {
326 if (aU[0] != 't' || aU[1] != 0) {printf("The only unit type supported is 't'\n");return -1;}
327 if (bU[0] != 't' || bU[1] != 0) {printf("The only unit type supported is 't'\n");return -1;}
328 housep->unbuilt.x = a * 16;
329 housep->unbuilt.y = b * 16;
330 } else { printf("Tile size must in `Nu Nu` format (N=number, u=unit(px,t))\n"); }
332 else
333 if (_eq("animation-idle")) {
334 rcfg_parse_frames(&housep->body, ANIM_BUILT, value);
336 else
337 if (_eq("animation-building")) {
338 rcfg_parse_frames(&housep->body, ANIM_BUILDING, value);
340 else
341 if (_eq("animation-working")) {
342 rcfg_parse_frames(&housep->body, ANIM_WORK, value);
344 else
345 if (_eq("animation-damaged")) {
346 rcfg_parse_frames(&housep->body, ANIM_DAMAGE, value);
348 else
349 if (_eq("animation-icon")) {
350 rcfg_parse_frames(&housep->body, ANIM_ICON, value);
352 else { printf(" Ignoring value %s = %s for house %d %s (%s)\n", name, value, num, housep->title, housep->id); }
353 return 0;
354 #undef _sveq
355 #undef _veq
356 #undef _eq
359 /** Units **/
360 int rcfg_units_count(dom_iter* this, void* ptr) {
362 int i;
363 for (i = 0; i < MAX_BUNITS; i++) {
364 unit_classes[i][0] = 0;
365 unit_p *unit = &bunits[i];
367 wipe_animation(&unit->body);
368 wipe_animation(&unit->face);
370 unit->body.image = ASS_LoadTexture("data/gfx/runelord.bmp", &white);
373 pseudo_marker[0] = 0;
375 return MAX_BUNITS;
378 int rcfg_units_pick(dom_iter* this, void* ptr) {
380 unit_p *unitp = ptr;
382 if (ptr == bunits) {
383 this->cursor = 0;
386 this->next = (unitp+1);
387 this->parent = NULL;
388 this->kids = NULL;
390 if (this->cursor++ > num_bunits) {
391 this->next = NULL;
394 return 0;
397 char* rcfg_units_test(void *ptr, const char *name) {
398 #define _eq(STR) (!strcasecmp(name, STR))
399 unit_p *unitp = ptr;
401 if (_eq("type")) return "unit";
403 if (_eq("num")) {
404 static char buf[12];
405 sprintf(buf, "%d", (unitp-bunits));
406 return buf;
409 if (_eq("id")) {
410 return unitp->id;
413 if (_eq("class")) {
414 return unit_classes[(unitp-bunits)];
417 //printf("Testing.. %s\n", name);
419 return "";
420 #undef _eq
423 int rcfg_units_apply(void *ptr, const char *name, const char *value) {
424 #define _eq(STR) (!strcasecmp(name, STR))
425 #define _veq(STR) (!strcasecmp(value, STR))
426 #define _sveq(STR) (!strcasecmp(subvalue, STR))
428 unit_p *unitp = ptr;
429 int num = (unitp - bunits);
431 if (_eq("id")) {
432 strncpy(unitp->id, value, LEN_UNIT_ID);
434 /* If we have a pseudo-mark, auto-apply it to this unit's class */
435 if (pseudo_marker[0]) {
436 char *cc = unit_classes[num];
437 strncat(cc, " ", sizeof(unit_classes[num]));
438 strncat(cc, pseudo_marker, sizeof(unit_classes[num]));
441 else
442 if (_eq("pseudo")) {
443 if (_veq("last")) {
444 num_bunits = num + 1;
445 if (num_bunits > MAX_BUNITS) num_bunits = MAX_BUNITS;
448 else
449 if (_eq("pseudo-mark")) {
450 strncpy(pseudo_marker, value, sizeof(pseudo_marker));
452 else
453 if (_eq("class")) {
455 char *cc = unit_classes[num];
456 strncat(cc, " ", sizeof(unit_classes[0]));
457 strncat(cc, value, sizeof(unit_classes[0]));
458 //printf("Attaching class: %s\n", value);
460 else
461 if (_eq("title")) {
462 strncpy(unitp->title, value, LEN_UNIT_TITLE);
464 else
465 if (_eq("stats")) {
466 int a,b,c,d,e,f;
467 if (sscanf(value, "%d %d %d %d %d %d", &a, &b, &c, &d, &e, &f) == 6) {
468 unitp->base_stat[0] = a;
469 unitp->base_stat[1] = b;
470 unitp->base_stat[2] = c;
471 unitp->base_stat[3] = d;
472 unitp->base_stat[4] = e;
473 unitp->base_stat[5] = f;
474 } else printf("Stats must be in 1 2 3 4 5 6 format (six space-separated numbers)\n");
476 else
477 if (_eq("str")) unitp->base_stat[0] = atoi(value);
478 else
479 if (_eq("dex")) unitp->base_stat[1] = atoi(value);
480 else
481 if (_eq("con")) unitp->base_stat[2] = atoi(value);
482 else
483 if (_eq("int")) unitp->base_stat[3] = atoi(value);
484 else
485 if (_eq("met")) unitp->base_stat[4] = atoi(value);
486 else
487 if (_eq("chr")) unitp->base_stat[5] = atoi(value);
488 else
489 if (_eq("skills")) {
490 int a,b,c,d,e,f;
491 if (sscanf(value, "%d %d %d %d %d %d", &a, &b, &c, &d, &e, &f) == 6) {
492 unitp->base_stat[6] = a;
493 unitp->base_stat[7] = b;
494 unitp->base_stat[8] = c;
495 unitp->base_stat[9] = d;
496 unitp->base_stat[10] = e;
497 unitp->base_stat[11] = f;
498 } else printf("Skills must be in 1 2 3 4 5 6 format (six space-separated numbers)\n");
500 else
501 if (_eq("perception")) {
502 if (_veq("sight")) {
503 unitp->perc = Sight;
505 else if (_veq("smell")) {
506 unitp->perc = Smell;
508 else fprintf(stderr, "Perception must be 'sight' or 'smell'\n");
510 else
511 if (_eq("modus")) {
512 if (_veq("none")) unitp->modus = MODUS_NONE;
513 else if (_veq("worker")) unitp->modus = MODUS_WORKER;
514 else if (_veq("hunter")) unitp->modus = MODUS_HUNTER;
515 else if (_veq("soldier")) unitp->modus = MODUS_SOLDIER;
516 else if (_veq("healer")) unitp->modus = MODUS_HEALER;
517 else if (_veq("carrier")) unitp->modus = MODUS_CARRIER;
518 else if (_veq("follower")) unitp->modus = MODUS_FOLLOWER;
519 else if (_veq("buffer")) unitp->modus = MODUS_BUFFER;
520 else if (_veq("debuffer")) unitp->modus = MODUS_DEBUFFER;
521 else if (_veq("explorer")) unitp->modus = MODUS_EXPLORER;
522 else fprintf(stderr, "Unrecognized modus operandi '%s'. See 'ai.h' MODUS_ defines.\n", value);
524 else
525 if (_eq("scent-human")) unitp->base_scent[SCENT_HUMAN] = atoi(value);
526 else
527 if (_eq("scent-animal")) unitp->base_scent[SCENT_ANIMAL] = atoi(value);
528 else
529 if (_eq("scent-magic")) unitp->base_scent[SCENT_MAGIC] = atoi(value);
530 else
531 if (!rcfg_apply_animation(&unitp->body, name, value)) {
532 //ok
534 else
535 if (_eq("animation-idle")) {
536 rcfg_parse_frames(&unitp->body, ANIM_IDLE, value);
538 else
539 if (_eq("animation-walk")) {
540 rcfg_parse_frames(&unitp->body, ANIM_WALK, value);
542 else
543 if (_eq("animation-carry")) {
544 rcfg_parse_frames(&unitp->body, ANIM_CARRY, value);
546 else
547 if (_eq("animation-attack")) {
548 rcfg_parse_frames(&unitp->body, ANIM_HIT, value);
550 else
551 if (_eq("animation-death")) {
552 rcfg_parse_frames(&unitp->body, ANIM_DEATH, value);
554 else
555 if (_eq("animation-face")) {
556 rcfg_parse_frames(&unitp->body, ANIM_FACE, value);
558 else printf(" Ignoring value %s = %s for unit %d %s (%s)\n", name, value, num, unitp->title, unitp->id);
559 return 0;
560 #undef _sveq
561 #undef _veq
562 #undef _eq
565 dom_iter rcfg_units_iterator = {
566 NULL,
567 NULL,
568 NULL,
569 NULL,
571 NULL,
572 NULL,
573 NULL,
576 &rcfg_units_count,
577 &rcfg_units_pick,
578 &rcfg_units_test,
579 &rcfg_units_apply,
582 dom_iter rcfg_house_iterator = {
583 NULL,
584 NULL,
585 NULL,
586 NULL,
588 NULL,
589 NULL,
590 NULL,
593 &rcfg_house_count,
594 &rcfg_house_pick,
595 &rcfg_house_test,
596 &rcfg_house_apply,
599 int cfg_load(const char *filename) {
601 css_ruleset *sheet;
603 SDL_RWops *file;
605 file = SDL_RWFromFile(filename, "rb");
606 if (file == NULL) return -1;
608 css_parser *state = css_parser_create();
610 char buf[1024];
611 int n, err;
612 while (1) {
613 n = SDL_RWread(file, buf, sizeof(char), sizeof(buf));
614 if (n <= 0) break;
616 err = css_parse(state, buf, n);
617 if (err) break;
620 SDL_RWclose(file);
622 sheet = css_parser_done(state);
623 if (sheet == NULL) return -1;
625 num_bunits = MAX_BUNITS;
626 num_bhouses = MAX_BHOUSES;
628 //css_fprintf(stdout, mainCSS);
629 css_cascade(&rcfg_units_iterator, &bunits, sheet);
630 css_cascade(&rcfg_house_iterator, &bhouses, sheet);
632 compute_units(&bunits, num_bunits);
633 compute_houses(&bhouses, num_bhouses);
635 return 0;