NetHackWiki:Skill table generator
Jump to navigation
Jump to search
Here's the program I used to generate Template:Weapon skill table, Template:Combat skill table, and Template:Spell skill table. -- Killian 07:39, 4 November 2006 (UTC)
modified_skills.h
should be a copy of skills.h, modified so that P_BARE_HANDS
and P_MARTIAL_ARTS
have separate numbers.
u_init_snippet.inc
should be the struct def_skill
definitions in u_init.c, from Skill_A[]
to Skill_W[]
.
#include <string> #include <iostream> #include <cctype> #include <vector> using std::string; using std::cout; using std::endl; using std::toupper; using std::vector; #define STEED #define TOURIST typedef signed char xchar; typedef int Skill; typedef int Level; #include "modified_skills.h" struct Role { const char *long_name; const char *short_name; const def_skill *skills; }; const char * skill_raw_name(const Skill &s) { switch (s) { case P_DAGGER: return "dagger"; case P_KNIFE: return "knife"; case P_AXE: return "axe"; case P_PICK_AXE: return "pick-axe"; case P_SHORT_SWORD: return "short sword"; case P_BROAD_SWORD: return "broadsword"; // !!! case P_LONG_SWORD: return "long sword"; case P_TWO_HANDED_SWORD: return "two-handed sword"; case P_SCIMITAR: return "scimitar"; case P_SABER: return "saber"; case P_CLUB: return "club"; case P_MACE: return "mace"; case P_MORNING_STAR: return "morning star"; case P_FLAIL: return "flail"; case P_HAMMER: return "hammer"; case P_QUARTERSTAFF: return "quarterstaff"; case P_POLEARMS: return "polearms"; case P_SPEAR: return "spear"; case P_JAVELIN: return "javelin"; case P_TRIDENT: return "trident"; case P_LANCE: return "lance"; case P_BOW: return "bow"; case P_SLING: return "sling"; case P_CROSSBOW: return "crossbow"; case P_DART: return "dart"; case P_SHURIKEN: return "shuriken"; case P_BOOMERANG: return "boomerang"; case P_WHIP: return "whip"; case P_UNICORN_HORN: return "unicorn horn"; case P_ATTACK_SPELL: return "attack"; case P_HEALING_SPELL: return "healing"; case P_DIVINATION_SPELL: return "divination"; case P_ENCHANTMENT_SPELL: return "enchantment"; case P_CLERIC_SPELL: return "clerical"; case P_ESCAPE_SPELL: return "escape"; case P_MATTER_SPELL: return "matter"; case P_BARE_HANDED_COMBAT: return "bare hands"; case P_MARTIAL_ARTS: return "martial arts"; case P_TWO_WEAPON_COMBAT: return "two weapon combat"; case P_RIDING: return "riding"; default: return "<STRANGE SKILL>"; } } const string init_cap(const string &c) { string s(c); string::iterator i = s.begin(); if (i != s.end()) { *i = toupper(*i); } return s; } const string skill_full_name(const Skill &s) { if (P_FIRST_WEAPON <= s && s <= P_LAST_WEAPON) { //return skill_raw_name(s) + string(" skill"); return skill_raw_name(s); } if (P_FIRST_SPELL <= s && s <= P_LAST_SPELL) { return skill_raw_name(s) + string(" spells"); } return string(skill_raw_name(s)); } const char * level_char(const Level &l) { switch (l) { case P_ISRESTRICTED: return "-"; case P_BASIC: return "b"; case P_SKILLED: return "''S''"; case P_EXPERT: return "'''E'''"; case P_MASTER: return "'''''M'''''"; case P_GRAND_MASTER: return "'''''GM'''''"; default: return "???"; } } const char * level_full(const Level &l) { switch (l) { case P_ISRESTRICTED: return "''(restricted)''"; case P_BASIC: return "Basic"; case P_SKILLED: return "Skilled"; case P_EXPERT: return "Expert"; case P_MASTER: return "Master"; case P_GRAND_MASTER: return "Grand Master"; default: return "???"; } } #include "u_init_snippet.inc" const int NUM_ROLES = 13; const Role ROLES[NUM_ROLES] = { { "Archeologist", "Arc", Skill_A }, { "Barbarian", "Bar", Skill_B }, { "Caveman", "Cav", Skill_C }, { "Healer", "Hea", Skill_H }, { "Knight", "Kni", Skill_K }, { "Monk", "Mon", Skill_Mon }, { "Priest", "Pri", Skill_P }, { "Rogue", "Rog", Skill_R }, { "Ranger", "Ran", Skill_Ran }, { "Samurai", "Sam", Skill_S }, { "Tourist", "Tou", Skill_T }, { "Valkyrie", "Val", Skill_V }, { "Wizard", "Wiz", Skill_W }, }; bool role_has_skill_level(const Role &r, const Skill &s, const Level &l) { for (const def_skill *sp = r.skills; sp->skill != P_NONE; ++sp) { if (sp->skill == s) { return sp->skmax == l; } } return l == P_ISRESTRICTED; } bool is_restricted(const Role &r, const Skill &s) { return role_has_skill_level(r, s, P_ISRESTRICTED); } bool role_has_level(const Role &r, const Level &l) { for (const def_skill *sp = r.skills; sp->skill != P_NONE; ++sp) { if (sp->skmax == l) { return true; } } return l == P_ISRESTRICTED; } void print_header(void) { cout << "! Skill \\ Role"; for (int i = 0; i < NUM_ROLES; i++) { const Role &r = ROLES[i]; cout << " !! [[" << r.long_name << "|" << r.short_name << "]]"; } cout << endl; } void print_role_skill_level( const Role &r, const Skill &s, const char *stringifier(const Skill &) ) { for (const def_skill *sp = r.skills; sp->skill != P_NONE; ++sp) { if (sp->skill == s) { cout << stringifier(sp->skmax); return; } } cout << stringifier(P_ISRESTRICTED); } void print_role_skill_level_char(const Role &r, const Skill &s) { print_role_skill_level(r, s, level_char); } void print_role_skill_level_full(const Role &r, const Skill &s) { print_role_skill_level(r, s, level_full); } void print_warning(void) { cout << "<!-- GENERATED PAGE; DO NOT EDIT DIRECTLY -->" << endl; } void print_noinclude(const char *category, const char *index) { cout << "<noinclude>" << endl; cout << "This page was generated using [[Wikihack:Skill table generator]]. " "Instead of editing this page, edit that program, and re-generate " "this page." << endl << endl << "[[Category:" << category << "|" << index << "]]" << endl << "</noinclude>" << endl; } string skill_link(const Skill &s) { return string("[[") + skill_full_name(s) + "|" + skill_raw_name(s) + "]]"; } void print_skill_link(const Skill &s) { cout << skill_link(s); } void print_role_skills(const Role &r, const Skill &first, const Skill &last) { for (Skill s = first; s <= last; ++s) { if (is_restricted(r, s)) { continue; } cout << "|-" << endl; cout << "| "; print_skill_link(s); cout << " || "; print_role_skill_level_full(r, s); cout << endl; } } void do_skill_table(const char *index, const Skill &first, const Skill &last) { print_warning(); cout << "{| class=\"prettytable\"" << endl; print_header(); for (Skill s = first; s <= last; ++s) { if (s == (P_LAST_WEAPON/2 + 1)) { cout << "|-" << endl; print_header(); } cout << "|-" << endl; cout << "|"; print_skill_link(s); for (int i = 0; i < NUM_ROLES; i++) { const Role &r = ROLES[i]; cout << " || "; print_role_skill_level_char(r, s); } cout << endl; } cout << "|}"; print_noinclude("Skill tables", index); } void do_role_skill_table(const Role &r) { print_warning(); cout << "{| class=\"prettytable\"" << endl; cout << "! colspan=\"2\" style=\"font-size:larger\" | " << r.long_name << " skills" << endl; cout << "|-" << endl; cout << "! Skill !! Maximum level" << endl; cout << "|-" << endl; cout << "| colspan=\"2\" align=\"center\" | ''Weapon skills''" << endl; print_role_skills(r, P_FIRST_WEAPON, P_LAST_WEAPON); cout << "|-" << endl; cout << "| colspan=\"2\" align=\"center\" | ''Combat skills''" << endl; print_role_skills(r, P_FIRST_H_TO_H, P_LAST_H_TO_H); cout << "|-" << endl; cout << "| colspan=\"2\" align=\"center\" | ''Spell skills''" << endl; print_role_skills(r, P_FIRST_SPELL, P_LAST_SPELL); cout << "|}"; print_noinclude("Skill tables", r.long_name); } void push_matches( const Role &r, const Skill &first, const Skill &last, const Level &l, vector<string> &v ) { for (Skill s = first; s <= last; ++s) { if (role_has_skill_level(r, s, l)) { v.push_back(skill_link(s)); } } } void print_matches(const char *heading, vector<string> &v) { if (!v.empty()) { cout << "* ''" << heading << ":'' "; for (vector<string>::iterator i = v.begin(); i != v.end(); ++i) { if (i != v.begin()) { cout << ", "; } cout << *i; } cout << endl; } } void do_role_skill_table_2(const Role &r) { print_warning(); cout << "{| class=\"prettytable\"" << endl; cout << "! colspan=\"2\" style=\"font-size:larger\" | " << r.long_name << " skills" << endl; cout << "|-" << endl; cout << "! Max !! Skills" << endl; for (Level l = P_BASIC; l <= P_GRAND_MASTER; l++) { if (!role_has_level(r, l)) { continue; } cout << "|-" << endl; cout << "| " << level_full(l) << endl; cout << "|" << endl; vector<string> weapon; push_matches(r, P_FIRST_WEAPON, P_LAST_WEAPON, l, weapon); print_matches("Weapons", weapon); vector<string> combat; push_matches(r, P_FIRST_H_TO_H, P_LAST_H_TO_H, l, combat); print_matches("Combat", combat); vector<string> spell; push_matches(r, P_FIRST_SPELL, P_LAST_SPELL, l, spell); print_matches("Spells", spell); } cout << "|}"; print_noinclude("Skill tables", r.long_name); } void do_skill_role_table(const Skill &s) { print_warning(); cout << "{| class=\"prettytable\"" << endl; cout << "! colspan=\"2\" style=\"font-size:larger\" | " << init_cap(skill_full_name(s)) << endl; cout << "|-" << endl; cout << "! Role !! Maximum level" << endl; for (int i = 0; i < NUM_ROLES; ++i) { const Role &r = ROLES[i]; if (is_restricted(r, s)) { continue; } cout << "|-" << endl; cout << "| [[" << r.long_name << "]]"; cout << " || "; print_role_skill_level_full(r, s); cout << endl; } cout << "|}"; string index(init_cap(skill_full_name(s))); print_noinclude("Skill-specific skill tables", index.c_str()); } bool some_role_has_level(const Skill &s, const Level &l) { for (int i = 0; i < NUM_ROLES; ++i) { const Role &r = ROLES[i]; for (const def_skill *sp = r.skills; sp->skill != P_NONE; ++sp) { if (sp->skill == s && sp->skmax == l) { return true; } } } return l == P_ISRESTRICTED; } void push_matching_roles(const Skill &s, const Level &l, vector<string> &v) { for (int i = 0; i < NUM_ROLES; ++i) { const Role &r = ROLES[i]; if (role_has_skill_level(r, s, l)) { v.push_back(string("[[") + r.long_name + "]]"); } } } void print_matching_roles(vector<string> &v) { if (!v.empty()) { cout << "* "; for (vector<string>::iterator i = v.begin(); i != v.end(); ++i) { if (i != v.begin()) { cout << ", "; } cout << *i; } cout << endl; } } void do_skill_role_table_2(const Skill &s) { print_warning(); cout << "{| class=\"prettytable\"" << endl; cout << "! colspan=\"2\" style=\"font-size:larger\" | " << init_cap(skill_full_name(s)) << endl; cout << "|-" << endl; cout << "! Max !! Role" << endl; for (Level l = P_BASIC; l <= P_GRAND_MASTER; l++) { if (!some_role_has_level(s, l)) { continue; } cout << "|-" << endl; cout << "| " << level_full(l) << endl; cout << "|" << endl; vector<string> roles; push_matching_roles(s, l, roles); print_matching_roles(roles); } cout << "|}"; string index(init_cap(skill_full_name(s))); print_noinclude("Skill-specific skill tables", index.c_str()); } void print_usage(const char *name) { cout << "Usage:" << endl << endl; cout << " " << name << " weapon|combat|spell" << endl; cout << " ==> overall weapon/combat/spell matrix" << endl << endl; cout << " " << name << " Role" << endl; cout << " ==> role-specific table (type A)" << endl << endl; cout << " " << name << " Rol" << endl; cout << " ==> role-specific table (type B)" << endl << endl; cout << " " << name << " \"skill\"" << endl; cout << " ==> skill-specific table" << endl; } int main(int argc, const char **argv) { if (argc == 2) { const string arg(argv[1]); if (arg == "weapon") { do_skill_table("Weapon", P_FIRST_WEAPON, P_LAST_WEAPON); } else if (arg == "combat") { do_skill_table("Combat", P_FIRST_H_TO_H, P_LAST_H_TO_H); } else if (arg == "spell") { do_skill_table("Spell", P_FIRST_SPELL, P_LAST_SPELL); } else { for (int i = 0; i < NUM_ROLES; ++i) { const Role &r = ROLES[i]; if (arg == r.short_name) { do_role_skill_table(r); exit(0); } else if (arg == r.long_name) { do_role_skill_table_2(r); exit(0); } } for (Skill s = 0; s < P_NUM_SKILLS; ++s) { if (arg == skill_raw_name(s)) { do_skill_role_table_2(s); exit(0); } } print_usage(argv[0]); } } else { print_usage(argv[0]); } }