00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #define LO_NEWFILE 2
00037 #define MAX_SIZE 64
00038 #define NA "n/a"
00039
00040 #include <time.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <global.h>
00044
00045 char *monster_page_head;
00046 char *monster_page_foot;
00047 char *monster_entry;
00048 char *monster_canuse_row;
00049 char *monster_protected_row;
00050 char *monster_vulnerable_row;
00051 char *monster_special_row;
00052 char *monster_attack_row;
00053 char *monster_lore_row;
00054
00055 typedef struct string_array {
00056 sint16 count;
00057 char **item;
00058 } String_Array;
00059
00069 const char *const flag_names[NUM_FLAGS+1] = {
00070 "alive", "wiz", NULL, NULL, "was_wiz", "applied", "unpaid",
00071 "can_use_shield", "no_pick", "client_anim_sync", "client_anim_random",
00072 "is_animated", NULL ,
00073 NULL , "monster", "friendly", "generator",
00074 "is_thrown", "auto_apply", "treasure", "player sold",
00075 "see_invisible", "can_roll", "overlay_floor",
00076 "is_turnable", NULL , NULL ,
00077 NULL , "is_used_up", "identified", "reflecting",
00078 "changing", "splitting", "hitback", "startequip",
00079 "blocksview", "undead", "scared", "unaggressive",
00080 "reflect_missile", "reflect_spell",
00081 "no_magic", "no_fix_player", "is_lightable", "tear_down",
00082 "run_away", NULL , NULL ,
00083 "pick_up", "unique", "no_drop",
00084 NULL , "can_cast_spell", "can_use_scroll", "can_use_range",
00085 "can_use_bow", "can_use_armour", "can_use_weapon",
00086 "can_use_ring", "has_ready_range", "has_ready_bow",
00087 "xrays", NULL, "is_floor", "lifesave", "no_strength", "sleep",
00088 "stand_still", "random_movement", "only_attack", "confused",
00089 "stealth", NULL, NULL, "cursed", "damned",
00090 "see_anywhere", "known_magical", "known_cursed",
00091 "can_use_skill", "been_applied",
00092 "has_ready_scroll", "can_use_rod", NULL,
00093 "can_use_horn", "make_invisible", "inv_locked", "is_wooded",
00094 "is_hilly", "has_ready_skill", "has_ready_weapon",
00095 "no_skill_ident", "is_blind", "can_see_in_dark", "is_cauldron",
00096 "is_dust", "no_steal", "one_hit", NULL, "berserk", "neutral",
00097 "no_attack", "no_damage", NULL, NULL, "activate_on_push",
00098 "activate_on_release", "is_water", "use_content_on_gen", NULL, "is_buildable",
00099 NULL, "blessed", "known_blessed"
00100 };
00101
00112 static char *cat_template(char *source, char *add) {
00113 if (!source)
00114 return add;
00115 source = realloc(source, strlen(source)+strlen(add)+1);
00116 strcat(source, add);
00117 free(add);
00118 return source;
00119 }
00120
00131 static int read_template(const char *name, char **buffer) {
00132 FILE *file;
00133 size_t size;
00134 struct stat info;
00135
00136 if (stat(name, &info)) {
00137 printf("Couldn't stat template %s!\n", name);
00138 return 1;
00139 }
00140
00141 (*buffer) = calloc(1, info.st_size+1);
00142 if (!(*buffer)) {
00143 printf("Template %s calloc failed!\n", name);
00144 return 1;
00145 }
00146
00147 if (info.st_size == 0) {
00148 (*buffer)[0] = '\0';
00149 return 0;
00150 }
00151
00152 file = fopen(name, "rb");
00153 if (!file) {
00154 printf("Couldn't open template %s!\n", name);
00155 free(*buffer);
00156 return 1;
00157 }
00158 if (fread(*buffer, info.st_size, 1, file) != 1) {
00159 printf("Couldn't read template %s!\n", name);
00160 free(*buffer);
00161 fclose(file);
00162 return 1;
00163 }
00164 fclose(file);
00165 return 0;
00166 }
00167
00185 static char *do_template(const char *template, const char **vars, const char **values) {
00186 int count = 0;
00187 const char *sharp = template;
00188 int maxlen = 0;
00189 int var = 0;
00190 char *result;
00191 char *current_result;
00192 const char *end;
00193
00194 while ((sharp = strchr(sharp, '#')) != NULL) {
00195 sharp++;
00196 count++;
00197 }
00198 if (!count)
00199 return strdup(template);
00200 if (count%2) {
00201 printf("Malformed template, mismatched #!\n");
00202 return strdup(template);
00203 }
00204
00205 while (vars[var] != NULL) {
00206 if (strlen(values[var]) > maxlen)
00207 maxlen = strlen(values[var]);
00208 var++;
00209 }
00210 result = calloc(1, strlen(template)+maxlen*(count/2)+1);
00211 if (!result)
00212 return NULL;
00213 current_result = result;
00214
00215 sharp = template;
00216 while ((sharp = strchr(sharp, '#')) != NULL) {
00217 end = strchr(sharp+1, '#');
00218 strncpy(current_result, template, sharp-template);
00219 if (end == sharp+1) {
00220 strcat(current_result, "#");
00221 } else {
00222 current_result = current_result+strlen(current_result);
00223 var = 0;
00224 while (vars[var] != 0 && strncmp(vars[var], sharp+1, end-sharp-1))
00225 var++;
00226 if (vars[var] == 0)
00227 printf("Wrong tag: %s\n", sharp);
00228 else
00229 strcpy(current_result, values[var]);
00230 }
00231 current_result = current_result+strlen(current_result);
00232 sharp = end+1;
00233 template = sharp;
00234 }
00235 strcat(current_result, template);
00236 return result;
00237 }
00238
00239
00240
00253 static void free_if_used(char *p) {
00254 if (p && strlen(p) > 0) {
00255 free(p);
00256 }
00257 }
00258
00271 static int sortbyname(const void *a, const void *b) {
00272 return (strcasecmp(*(const char **)a, *(const char **)b));
00273 }
00274
00288 static int sort_archetypes(const void *a, const void *b) {
00289 archetype *aa;
00290 archetype *bb;
00291
00292 aa = *(archetype **)a;
00293 bb = *(archetype **)b;
00294
00295 return (strcasecmp(aa->clone.name, bb->clone.name));
00296 }
00297
00310 void push(String_Array *array, const char *string) {
00311 sint16 i = array->count;
00312
00313 array->item[i] = strdup_local(string);
00314 array->count++;
00315 }
00316
00325 void free_data(String_Array *array) {
00326 int item;
00327
00328 for (item = 0; item < array->count; item++)
00329 free(array->item[item]);
00330 free(array->item);
00331 array->item = NULL;
00332 }
00333
00344 const char *join_with_comma(String_Array *array) {
00345 char *newtext;
00346 int i;
00347
00348 newtext = calloc(1, 1);
00349 qsort(array->item, array->count, sizeof(char *), sortbyname);
00350 for (i = 0; i < array->count; i++) {
00351 if (i) {
00352 newtext = realloc(newtext, strlen(newtext)+strlen(", ")+1);
00353 newtext = strncat(newtext, ", ", 2);
00354 }
00355 newtext = realloc(newtext, strlen(newtext)+strlen(array->item[i])+1);
00356 newtext = strncat(newtext, array->item[i], strlen(array->item[i]));
00357 }
00358 return newtext;
00359 }
00360
00361 int main(int argc, char *argv[]) {
00362
00363 archetype *at;
00364 int archnum = 0;
00365 archetype *monster[4000];
00366 int i;
00367 char letter;
00368 char last_letter;
00369 char *wiki_page = NULL;
00370 char *monster_entries = NULL;
00371
00372 FILE *fp = NULL;
00373 FILE *image_list;
00374 char image_list_path[128];
00375 char wikifile[128];
00376 char *template;
00377
00378 const char *wikidir = "/tmp";
00379
00380 init_globals();
00381 init_library();
00382 init_archetypes();
00383 init_artifacts();
00384 init_formulae();
00385 init_readable();
00386
00387 init_gods();
00388
00389
00390 if (read_template("templates/wiki/monster_page_head", &monster_page_head))
00391 return;
00392 if (read_template("templates/wiki/monster_page_foot", &monster_page_foot))
00393 return;
00394 if (read_template("templates/wiki/monster_entry", &monster_entry))
00395 return;
00396 if (read_template("templates/wiki/monster_canuse_row", &monster_canuse_row))
00397 return;
00398 if (read_template("templates/wiki/monster_protected_row", &monster_protected_row))
00399 return;
00400 if (read_template("templates/wiki/monster_vulnerable_row", &monster_vulnerable_row))
00401 return;
00402 if (read_template("templates/wiki/monster_special_row", &monster_special_row))
00403 return;
00404 if (read_template("templates/wiki/monster_attack_row", &monster_attack_row))
00405 return;
00406 if (read_template("templates/wiki/monster_lore_row", &monster_lore_row))
00407 return;
00408 sprintf(image_list_path, "%s/image_list", wikidir);
00409 image_list = fopen(image_list_path, "w");
00410 if (!image_list) {
00411 LOG(llevError, "Unable to open image list file!\n");
00412 exit(1);
00413 }
00414
00415
00416 for (at = first_archetype; at != NULL; at = at->next) {
00417 if (QUERY_FLAG(&at->clone, FLAG_MONSTER)
00418 && QUERY_FLAG(&at->clone, FLAG_ALIVE)) {
00419 monster[archnum++] = at;
00420 }
00421 }
00422 printf("Sorting...");
00423
00424 qsort(&monster[0], archnum, sizeof(archetype *), sort_archetypes);
00425 printf("done. %i items found\n", archnum);
00426
00427 last_letter = '\0';
00428
00429 for (i = 0; i < archnum; i++) {
00430 at = monster[i];
00431 if (at) {
00432 const char *key[16] = { NULL, };
00433 const char *val[16] = { NULL, };
00434 char buf[16][MAX_BUF];
00435 int keycount = 0;
00436 int res;
00437
00438 letter = tolower(at->clone.name[0]);
00439
00440 LOG(llevInfo, "Doing archetype %s\n", at->name);
00441
00442 if (letter != last_letter) {
00443 if (fp) {
00444 keycount = 0;
00445 key[keycount] = NULL;
00446 template = do_template(monster_page_foot, key, val);
00447 res = fprintf(fp, "%s", template);
00448 free(template);
00449 template = NULL;
00450 if (res < 0) {
00451 LOG(llevError, "Unable to write to file!\n");
00452 }
00453 fclose(fp);
00454 }
00455
00456 snprintf(wikifile, sizeof(wikifile), "%s/%c", wikidir, letter);
00457 fp = fopen(wikifile, "w");
00458 if (!fp) {
00459 fprintf(stderr, "Unable to write to wiki file!\n");
00460 exit(1);
00461 }
00462
00463 char letterindex[256] = "";
00464 char letterindexnext[7];
00465 char li;
00466 letterindexnext[0] = '\0';
00467 for (li = 'a'; li <= 'z'; li++) {
00468 if (li == letter) {
00469 sprintf(letterindexnext, "%c ", toupper(li));
00470 } else {
00471 sprintf(letterindexnext, "[[%c]] ", toupper(li));
00472 }
00473 strncat(letterindex, letterindexnext, 256);
00474 }
00475
00476 keycount = 0;
00477 key[keycount] = "LETTER";
00478 sprintf(buf[keycount], "%c", toupper(letter));
00479 val[keycount++] = buf[keycount];
00480 key[keycount] = "LETTERINDEX";
00481 val[keycount++] = letterindex;
00482 key[keycount] = NULL;
00483 template = do_template(monster_page_head, key, val);
00484 res = fprintf(fp, template);
00485 free(template);
00486 if (res < 0) {
00487 LOG(llevError, "Unable to write to file!");
00488 }
00489 last_letter = letter;
00490 }
00491
00492
00493 char *canuse_row;
00494 char *protected_row;
00495 char *vulnerable_row;
00496 char *special_row;
00497 char *attack_row;
00498 char *lore_row;
00499 const int CANUSE_LENGTH = 16;
00500 String_Array canuse;
00501 String_Array resist;
00502 String_Array vulner;
00503 String_Array attack;
00504 String_Array special;
00505
00506
00507
00508
00509 const sint8 special_flags[] = { 21, 93, 52, 38, 13, 32, 61, -1 };
00510 const char *special_names[] = {
00511 "see invisible",
00512 "see in dark",
00513 "spellcaster",
00514 "unaggressive",
00515 "flying",
00516 "splitting",
00517 "x-ray vision"
00518 };
00519 int j;
00520
00521 canuse.item = calloc(1, sizeof(const char *)*(CANUSE_LENGTH+1));
00522 resist.item = calloc(1, sizeof(const char *)*(NROFATTACKS+1));
00523 vulner.item = calloc(1, sizeof(const char *)*(NROFATTACKS+1));
00524 attack.item = calloc(1, sizeof(const char *)*(NROFATTACKS+1));
00525 special.item = calloc(1, sizeof(const char *)*(NROFATTACKS+1));
00526
00527
00528 if (at->clone.lore) {
00529 key[keycount] = "LORE";
00530 key[keycount+1] = NULL;
00531 val[keycount] = at->clone.lore;
00532 keycount++;
00533 lore_row = do_template(monster_lore_row, key, val);
00534 } else
00535 lore_row = strdup("");
00536
00537
00538 canuse.count = 0;
00539 keycount = 0;
00540 for (j = 1; j <= NUM_FLAGS; j++) {
00541 if (QUERY_FLAG(&at->clone, j)
00542 && flag_names[j]
00543 && !strncmp(flag_names[j], "can_use_", 8)) {
00544 push(&canuse, flag_names[j]+8);
00545 }
00546 }
00547 if (canuse.count) {
00548 key[keycount] = "CANUSE";
00549 key[keycount+1] = NULL;
00550 val[keycount] = join_with_comma(&canuse);
00551 canuse_row = do_template(monster_canuse_row, key, val);
00552 free(val[keycount]);
00553 } else
00554 canuse_row = strdup("");
00555
00556
00557 resist.count = 0;
00558 vulner.count = 0;
00559 for (j = 0; j <= NROFATTACKS; j++) {
00560 if (at->clone.resist[j] && attacktype_desc[j]) {
00561 char rowtext[32];
00562
00563 if (at->clone.resist[j] < 0) {
00564 sprintf(rowtext, "%s %i", attacktype_desc[j], at->clone.resist[j]);
00565 push(&vulner, rowtext);
00566 } else {
00567 sprintf(rowtext, "%s +%i", attacktype_desc[j], at->clone.resist[j]);
00568 push(&resist, rowtext);
00569 }
00570 }
00571 }
00572 keycount = 0;
00573 if (resist.count) {
00574 key[keycount] = "PROTECTED";
00575 key[keycount+1] = NULL;
00576 val[keycount] = join_with_comma(&resist);
00577 protected_row = do_template(monster_protected_row, key, val);
00578 free(val[keycount]);
00579 } else
00580 protected_row = strdup("");
00581
00582 keycount = 0;
00583 if (vulner.count) {
00584 key[keycount] = "VULNERABLE";
00585 key[keycount+1] = NULL;
00586 val[keycount] = join_with_comma(&vulner);
00587 vulnerable_row = do_template(monster_vulnerable_row, key, val);
00588 free(val[keycount]);
00589 } else
00590 vulnerable_row = strdup("");
00591
00592
00593 attack.count = 0;
00594 keycount = 0;
00595 val[keycount] = NULL;
00596 for (j = 0; j <= NROFATTACKS; j++) {
00597 if (at->clone.attacktype&(1U<<j)) {
00598 push(&attack, attacktype_desc[j]);
00599 }
00600 }
00601 if (attack.count) {
00602 key[keycount] = "ATTACKS";
00603 key[keycount+1] = NULL;
00604 val[keycount] = join_with_comma(&attack);
00605 attack_row = do_template(monster_attack_row, key, val);
00606 free(val[keycount]);
00607 } else
00608 attack_row = strdup("");
00609
00610
00611 special.count = 0;
00612 keycount = 0;
00613 val[keycount] = NULL;
00614 for (j = 0; special_flags[j] >= 0; j++) {
00615 if (QUERY_FLAG(&at->clone, special_flags[j])) {
00616 push(&special, special_names[j]);
00617 }
00618 }
00619 if (special.count) {
00620 key[keycount] = "SPECIAL";
00621 key[keycount+1] = NULL;
00622 val[keycount] = join_with_comma(&special);
00623 special_row = do_template(monster_special_row, key, val);
00624 free(val[keycount]);
00625 } else
00626 special_row = strdup("");
00627
00628 keycount = 0;
00629 key[keycount] = "CANUSEROW";
00630 val[keycount++] = canuse_row;
00631 key[keycount] = "PROTECTEDROW";
00632 val[keycount++] = protected_row;
00633 key[keycount] = "VULNERABLEROW";
00634 val[keycount++] = vulnerable_row;
00635 key[keycount] = "SPECIALROW";
00636 val[keycount++] = attack_row;
00637 key[keycount] = "ATTACKROW";
00638 val[keycount++] = special_row;
00639 key[keycount] = "LOREROW";
00640 val[keycount++] = lore_row;
00641 key[keycount] = "XP";
00642 sprintf(buf[keycount], "%li", at->clone.stats.exp);
00643 val[keycount++] = buf[keycount];
00644 key[keycount] = "HP";
00645 sprintf(buf[keycount], "%i", at->clone.stats.hp);
00646 val[keycount++] = buf[keycount];
00647 key[keycount] = "AC";
00648 sprintf(buf[keycount], "%i", at->clone.stats.ac);
00649 val[keycount++] = buf[keycount];
00650 key[keycount] = "NAME";
00651 val[keycount++] = at->clone.name;
00652 key[keycount] = "RACE";
00653 if (at->clone.race) {
00654 val[keycount++] = at->clone.race;
00655 } else {
00656 val[keycount++] = NA;
00657 }
00658 if (at->clone.face->name) {
00659 key[keycount] = "FACE";
00660 sprintf(buf[keycount], "{{http://aaron.baugher.biz/images/cf/%s.png}}", at->clone.face->name);
00661 val[keycount++] = buf[keycount];
00662 sprintf(buf[keycount], "%s.png\n", at->clone.face->name);
00663 fprintf(image_list, buf[keycount]);
00664 }
00665
00666 key[keycount] = "GENFACE";
00667 val[keycount++] = "";
00668 key[keycount] = NULL;
00669
00670 template = do_template(monster_entry, key, val);
00671 fprintf(fp, template);
00672 free(template);
00673 template = NULL;
00674
00675 free_data(&canuse);
00676 free_data(&resist);
00677 free_data(&vulner);
00678 free_data(&attack);
00679 free_data(&special);
00680 free(canuse_row);
00681 free(protected_row);
00682 free(vulnerable_row);
00683 free(attack_row);
00684 free(special_row);
00685 free(lore_row);
00686 } else {
00687 LOG(llevError, "Something is very wrong.\n");
00688 }
00689 }
00690 fclose(image_list);
00691 }
00692
00693 void set_map_timeout(void) {
00694
00695 }
00696
00697 #include <global.h>
00698
00699
00700
00701 int auto_apply(object *op) {
00702 object *tmp = NULL;
00703 int i;
00704
00705 switch (op->type) {
00706 case SHOP_FLOOR:
00707 if (!HAS_RANDOM_ITEMS(op))
00708 return 0;
00709 do {
00710 i = 10;
00711 while ((tmp = generate_treasure(op->randomitems, op->stats.exp ? op->stats.exp : 5)) == NULL && --i)
00712 ;
00713 if (tmp == NULL)
00714 return 0;
00715 if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
00716 free_object(tmp);
00717 tmp = NULL;
00718 }
00719 } while (!tmp);
00720
00721 tmp->x = op->x,
00722 tmp->y = op->y;
00723 SET_FLAG(tmp, FLAG_UNPAID);
00724 insert_ob_in_map(tmp, op->map, NULL, 0);
00725 CLEAR_FLAG(op, FLAG_AUTO_APPLY);
00726 identify(tmp);
00727 break;
00728
00729 case TREASURE:
00730 if (HAS_RANDOM_ITEMS(op))
00731 while ((op->stats.hp--) > 0)
00732 create_treasure(op->randomitems, op, GT_ENVIRONMENT, op->stats.exp ? op->stats.exp : op->map == NULL ? 14 : op->map->difficulty, 0);
00733 remove_ob(op);
00734 free_object(op);
00735 break;
00736 }
00737
00738 return tmp ? 1 : 0;
00739 }
00740
00741
00742
00743
00744
00745
00746 void fix_auto_apply(mapstruct *m) {
00747 object *tmp, *above = NULL;
00748 int x, y;
00749
00750 for (x = 0; x < MAP_WIDTH(m); x++)
00751 for (y = 0; y < MAP_HEIGHT(m); y++)
00752 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = above) {
00753 above = tmp->above;
00754
00755 if (QUERY_FLAG(tmp, FLAG_AUTO_APPLY))
00756 auto_apply(tmp);
00757 else if (tmp->type == TREASURE) {
00758 if (HAS_RANDOM_ITEMS(tmp))
00759 while ((tmp->stats.hp--) > 0)
00760 create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
00761 }
00762 if (tmp
00763 && tmp->arch
00764 && tmp->type != PLAYER
00765 && tmp->type != TREASURE
00766 && tmp->randomitems) {
00767 if (tmp->type == CONTAINER) {
00768 if (HAS_RANDOM_ITEMS(tmp))
00769 while ((tmp->stats.hp--) > 0)
00770 create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
00771 } else if (HAS_RANDOM_ITEMS(tmp))
00772 create_treasure(tmp->randomitems, tmp, GT_APPLY, m->difficulty, 0);
00773 }
00774 }
00775 for (x = 0; x < MAP_WIDTH(m); x++)
00776 for (y = 0; y < MAP_HEIGHT(m); y++)
00777 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
00778 if (tmp->above
00779 && (tmp->type == TRIGGER_BUTTON || tmp->type == TRIGGER_PEDESTAL))
00780 check_trigger(tmp, tmp->above);
00781 }
00782
00783 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00784
00790 void draw_ext_info(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *txt, const char *txt2) {
00791 fprintf(logfile, "%s\n", txt);
00792 }
00793
00794 void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format, ...) {
00795 va_list ap;
00796 va_start(ap, old_format);
00797 vfprintf(logfile, old_format, ap);
00798 va_end(ap);
00799 }
00800
00801 void ext_info_map(int color, const mapstruct *map, uint8 type, uint8 subtype, const char *str1, const char *str2) {
00802 fprintf(logfile, "ext_info_map: %s\n", str2);
00803 }
00804
00805 void move_firewall(object *ob) {
00806 }
00807
00808 void emergency_save(int x) {
00809 }
00810
00811 void clean_tmp_files(void) {
00812 }
00813
00814 void esrv_send_item(object *ob, object *obx) {
00815 }
00816
00817 void dragon_ability_gain(object *ob, int x, int y) {
00818 }
00819
00820 void set_darkness_map(mapstruct *m) {
00821 }
00822
00823 object *find_skill_by_number(object *who, int skillno) {
00824 return NULL;
00825 }
00826
00827 void esrv_del_item(player *pl, int tag) {
00828 }
00829
00830 void esrv_update_spells(player *pl) {
00831 }
00832
00833 void monster_check_apply(object *ob, object *obt) {
00834 }
00835
00836 void trap_adjust(object *ob, int x) {
00837 }
00838
00839 int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix) {
00840 return 0;
00841 }
00842
00843 int execute_global_event(int eventcode, ...) {
00844 return 0;
00845 }
00846 #endif