Difference between revisions of "NetHackWiki:Skill table generator"
(missing include, and slightly improved howto) |
(update the code to allow styling the skill table cells.) |
||
Line 78: | Line 78: | ||
case P_WHIP: return "whip"; | case P_WHIP: return "whip"; | ||
case P_UNICORN_HORN: return "unicorn horn"; | case P_UNICORN_HORN: return "unicorn horn"; | ||
− | + | ||
case P_ATTACK_SPELL: return "attack"; | case P_ATTACK_SPELL: return "attack"; | ||
case P_HEALING_SPELL: return "healing"; | case P_HEALING_SPELL: return "healing"; | ||
Line 86: | Line 86: | ||
case P_ESCAPE_SPELL: return "escape"; | case P_ESCAPE_SPELL: return "escape"; | ||
case P_MATTER_SPELL: return "matter"; | case P_MATTER_SPELL: return "matter"; | ||
− | + | ||
case P_BARE_HANDED_COMBAT: return "bare hands"; | case P_BARE_HANDED_COMBAT: return "bare hands"; | ||
case P_MARTIAL_ARTS: return "martial arts"; | case P_MARTIAL_ARTS: return "martial arts"; | ||
Line 99: | Line 99: | ||
init_cap(const string &c) { | init_cap(const string &c) { | ||
string s(c); | string s(c); | ||
− | + | ||
string::iterator i = s.begin(); | string::iterator i = s.begin(); | ||
− | + | ||
if (i != s.end()) { *i = toupper(*i); } | if (i != s.end()) { *i = toupper(*i); } | ||
− | + | ||
return s; | return s; | ||
} | } | ||
Line 113: | Line 113: | ||
return skill_raw_name(s); | return skill_raw_name(s); | ||
} | } | ||
− | + | ||
if (P_FIRST_SPELL <= s && s <= P_LAST_SPELL) { | if (P_FIRST_SPELL <= s && s <= P_LAST_SPELL) { | ||
return skill_raw_name(s) + string(" spells"); | return skill_raw_name(s) + string(" spells"); | ||
} | } | ||
− | + | ||
return string(skill_raw_name(s)); | return string(skill_raw_name(s)); | ||
} | } | ||
Line 144: | Line 144: | ||
case P_GRAND_MASTER: return "Grand Master"; | case P_GRAND_MASTER: return "Grand Master"; | ||
default: return "???"; | default: return "???"; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | const char * | ||
+ | level_span_class(const Level &l) { | ||
+ | switch (l) { | ||
+ | case P_ISRESTRICTED: return "class=\"restricted\""; | ||
+ | case P_BASIC: return "class=\"basic\""; | ||
+ | case P_SKILLED: return "class=\"skilled\""; | ||
+ | case P_EXPERT: return "class=\"expert\""; | ||
+ | case P_MASTER: return "class=\"master\""; | ||
+ | case P_GRAND_MASTER: return "class=\"grandmaster\""; | ||
+ | default: return "class=\"unknown_skill\""; | ||
} | } | ||
} | } | ||
Line 197: | Line 210: | ||
for (int i = 0; i < NUM_ROLES; i++) { | for (int i = 0; i < NUM_ROLES; i++) { | ||
const Role &r = ROLES[i]; | const Role &r = ROLES[i]; | ||
− | + | ||
cout << " !! [[" << r.long_name << "|" << r.short_name << "]]"; | cout << " !! [[" << r.long_name << "|" << r.short_name << "]]"; | ||
} | } | ||
− | + | ||
cout << endl; | cout << endl; | ||
} | } | ||
Line 216: | Line 229: | ||
} | } | ||
} | } | ||
− | + | ||
cout << stringifier(P_ISRESTRICTED); | cout << stringifier(P_ISRESTRICTED); | ||
} | } | ||
Line 228: | Line 241: | ||
print_role_skill_level_full(const Role &r, const Skill &s) { | print_role_skill_level_full(const Role &r, const Skill &s) { | ||
print_role_skill_level(r, s, level_full); | print_role_skill_level(r, s, level_full); | ||
− | } | + | } |
+ | |||
+ | void | ||
+ | print_role_skill_level_span_class(const Role &r, const Skill &s) { | ||
+ | print_role_skill_level(r, s, level_span_class); | ||
+ | } | ||
+ | |||
void | void | ||
Line 238: | Line 257: | ||
print_noinclude(const char *category, const char *index) { | print_noinclude(const char *category, const char *index) { | ||
cout << "<noinclude>" << endl; | cout << "<noinclude>" << endl; | ||
− | + | ||
cout << | cout << | ||
"This page was generated using [[NetHackWiki:Skill table generator]]. " | "This page was generated using [[NetHackWiki:Skill table generator]]. " | ||
Line 265: | Line 284: | ||
for (Skill s = first; s <= last; ++s) { | for (Skill s = first; s <= last; ++s) { | ||
if (is_restricted(r, s)) { continue; } | if (is_restricted(r, s)) { continue; } | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "| "; | cout << "| "; | ||
− | + | ||
print_skill_link(s); | print_skill_link(s); | ||
− | + | ||
cout << " || "; | cout << " || "; | ||
print_role_skill_level_full(r, s); | print_role_skill_level_full(r, s); | ||
Line 281: | Line 300: | ||
print_warning(); | print_warning(); | ||
− | cout << "{| class=\"prettytable\"" << endl; | + | cout << "{| class=\"prettytable " << index << "-skilltable\"" << endl; |
− | + | ||
print_header(); | print_header(); | ||
− | + | ||
for (Skill s = first; s <= last; ++s) { | for (Skill s = first; s <= last; ++s) { | ||
− | + | ||
if (s == (P_LAST_WEAPON/2 + 1)) { | if (s == (P_LAST_WEAPON/2 + 1)) { | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
print_header(); | print_header(); | ||
} | } | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "|"; | cout << "|"; | ||
− | + | ||
print_skill_link(s); | print_skill_link(s); | ||
− | + | ||
for (int i = 0; i < NUM_ROLES; i++) { | for (int i = 0; i < NUM_ROLES; i++) { | ||
const Role &r = ROLES[i]; | const Role &r = ROLES[i]; | ||
− | + | ||
− | cout << " || "; | + | cout << "\n|"; |
+ | print_role_skill_level_span_class(r, s); | ||
+ | cout << "| "; | ||
print_role_skill_level_char(r, s); | print_role_skill_level_char(r, s); | ||
} | } | ||
− | + | ||
cout << endl; | cout << endl; | ||
} | } | ||
− | + | ||
− | cout << "|}"; | + | cout << "|}\n"; |
− | |||
print_noinclude("Skill tables", index); | print_noinclude("Skill tables", index); | ||
} | } | ||
Line 316: | Line 336: | ||
do_role_skill_table(const Role &r) { | do_role_skill_table(const Role &r) { | ||
print_warning(); | print_warning(); | ||
− | + | ||
cout << "{| class=\"prettytable\"" << endl; | cout << "{| class=\"prettytable\"" << endl; | ||
− | + | ||
cout << "! colspan=\"2\" style=\"font-size:larger\" | " | cout << "! colspan=\"2\" style=\"font-size:larger\" | " | ||
<< r.long_name << " skills" << endl; | << r.long_name << " skills" << endl; | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "! Skill !! Maximum level" << endl; | cout << "! Skill !! Maximum level" << endl; | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "| colspan=\"2\" align=\"center\" | ''Weapon skills''" << endl; | cout << "| colspan=\"2\" align=\"center\" | ''Weapon skills''" << endl; | ||
− | + | ||
print_role_skills(r, P_FIRST_WEAPON, P_LAST_WEAPON); | print_role_skills(r, P_FIRST_WEAPON, P_LAST_WEAPON); | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "| colspan=\"2\" align=\"center\" | ''Combat skills''" << endl; | cout << "| colspan=\"2\" align=\"center\" | ''Combat skills''" << endl; | ||
− | + | ||
print_role_skills(r, P_FIRST_H_TO_H, P_LAST_H_TO_H); | print_role_skills(r, P_FIRST_H_TO_H, P_LAST_H_TO_H); | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "| colspan=\"2\" align=\"center\" | ''Spell skills''" << endl; | cout << "| colspan=\"2\" align=\"center\" | ''Spell skills''" << endl; | ||
print_role_skills(r, P_FIRST_SPELL, P_LAST_SPELL); | print_role_skills(r, P_FIRST_SPELL, P_LAST_SPELL); | ||
− | + | ||
cout << "|}"; | cout << "|}"; | ||
− | + | ||
print_noinclude("Skill tables", r.long_name); | print_noinclude("Skill tables", r.long_name); | ||
} | } | ||
Line 368: | Line 388: | ||
cout << ", "; | cout << ", "; | ||
} | } | ||
− | + | ||
cout << *i; | cout << *i; | ||
} | } | ||
Line 378: | Line 398: | ||
do_role_skill_table_2(const Role &r) { | do_role_skill_table_2(const Role &r) { | ||
print_warning(); | print_warning(); | ||
− | + | ||
cout << "{| class=\"prettytable\"" << endl; | cout << "{| class=\"prettytable\"" << endl; | ||
− | + | ||
cout << "! colspan=\"2\" style=\"font-size:larger\" | " | cout << "! colspan=\"2\" style=\"font-size:larger\" | " | ||
<< r.long_name << " skills" << endl; | << r.long_name << " skills" << endl; | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "! Max !! Skills" << endl; | cout << "! Max !! Skills" << endl; | ||
− | + | ||
for (Level l = P_BASIC; l <= P_GRAND_MASTER; l++) { | for (Level l = P_BASIC; l <= P_GRAND_MASTER; l++) { | ||
if (!role_has_level(r, l)) { continue; } | if (!role_has_level(r, l)) { continue; } | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "| " << level_full(l) << endl; | cout << "| " << level_full(l) << endl; | ||
− | + | ||
cout << "|" << endl; | cout << "|" << endl; | ||
− | + | ||
vector<string> weapon; | vector<string> weapon; | ||
push_matches(r, P_FIRST_WEAPON, P_LAST_WEAPON, l, weapon); | push_matches(r, P_FIRST_WEAPON, P_LAST_WEAPON, l, weapon); | ||
print_matches("Weapons", weapon); | print_matches("Weapons", weapon); | ||
− | + | ||
vector<string> combat; | vector<string> combat; | ||
push_matches(r, P_FIRST_H_TO_H, P_LAST_H_TO_H, l, combat); | push_matches(r, P_FIRST_H_TO_H, P_LAST_H_TO_H, l, combat); | ||
print_matches("Combat", combat); | print_matches("Combat", combat); | ||
− | + | ||
vector<string> spell; | vector<string> spell; | ||
push_matches(r, P_FIRST_SPELL, P_LAST_SPELL, l, spell); | push_matches(r, P_FIRST_SPELL, P_LAST_SPELL, l, spell); | ||
print_matches("Spells", spell); | print_matches("Spells", spell); | ||
} | } | ||
− | + | ||
cout << "|}"; | cout << "|}"; | ||
− | + | ||
print_noinclude("Skill tables", r.long_name); | print_noinclude("Skill tables", r.long_name); | ||
} | } | ||
Line 416: | Line 436: | ||
do_skill_role_table(const Skill &s) { | do_skill_role_table(const Skill &s) { | ||
print_warning(); | print_warning(); | ||
− | + | ||
cout << "{| class=\"prettytable\"" << endl; | cout << "{| class=\"prettytable\"" << endl; | ||
− | + | ||
− | cout << "! colspan=\"2\" style=\"font-size:larger\" | " | + | cout << "! colspan=\"2\" style=\"font-size:larger\" | " |
<< init_cap(skill_full_name(s)) << endl; | << init_cap(skill_full_name(s)) << endl; | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "! Role !! Maximum level" << endl; | cout << "! Role !! Maximum level" << endl; | ||
− | + | ||
for (int i = 0; i < NUM_ROLES; ++i) { | for (int i = 0; i < NUM_ROLES; ++i) { | ||
const Role &r = ROLES[i]; | const Role &r = ROLES[i]; | ||
− | + | ||
if (is_restricted(r, s)) { continue; } | if (is_restricted(r, s)) { continue; } | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "| [[" << r.long_name << "]]"; | cout << "| [[" << r.long_name << "]]"; | ||
Line 436: | Line 456: | ||
cout << endl; | cout << endl; | ||
} | } | ||
− | + | ||
cout << "|}"; | cout << "|}"; | ||
− | + | ||
string index(init_cap(skill_full_name(s))); | string index(init_cap(skill_full_name(s))); | ||
print_noinclude("Skill-specific skill tables", index.c_str()); | print_noinclude("Skill-specific skill tables", index.c_str()); | ||
Line 447: | Line 467: | ||
for (int i = 0; i < NUM_ROLES; ++i) { | for (int i = 0; i < NUM_ROLES; ++i) { | ||
const Role &r = ROLES[i]; | const Role &r = ROLES[i]; | ||
− | + | ||
for (const def_skill *sp = r.skills; sp->skill != P_NONE; ++sp) { | for (const def_skill *sp = r.skills; sp->skill != P_NONE; ++sp) { | ||
if (sp->skill == s && sp->skmax == l) { | if (sp->skill == s && sp->skmax == l) { | ||
Line 454: | Line 474: | ||
} | } | ||
} | } | ||
− | + | ||
return l == P_ISRESTRICTED; | return l == P_ISRESTRICTED; | ||
} | } | ||
Line 462: | Line 482: | ||
for (int i = 0; i < NUM_ROLES; ++i) { | for (int i = 0; i < NUM_ROLES; ++i) { | ||
const Role &r = ROLES[i]; | const Role &r = ROLES[i]; | ||
− | + | ||
if (role_has_skill_level(r, s, l)) { | if (role_has_skill_level(r, s, l)) { | ||
v.push_back(string("[[") + r.long_name + "]]"); | v.push_back(string("[[") + r.long_name + "]]"); | ||
Line 473: | Line 493: | ||
if (!v.empty()) { | if (!v.empty()) { | ||
cout << "* "; | cout << "* "; | ||
− | + | ||
for (vector<string>::iterator i = v.begin(); i != v.end(); ++i) { | for (vector<string>::iterator i = v.begin(); i != v.end(); ++i) { | ||
if (i != v.begin()) { | if (i != v.begin()) { | ||
cout << ", "; | cout << ", "; | ||
} | } | ||
− | + | ||
cout << *i; | cout << *i; | ||
} | } | ||
cout << endl; | cout << endl; | ||
} | } | ||
− | } | + | } |
void | void | ||
do_skill_role_table_2(const Skill &s) { | do_skill_role_table_2(const Skill &s) { | ||
print_warning(); | print_warning(); | ||
− | + | ||
cout << "{| class=\"prettytable\"" << endl; | cout << "{| class=\"prettytable\"" << endl; | ||
− | + | ||
− | cout << "! colspan=\"2\" style=\"font-size:larger\" | " | + | cout << "! colspan=\"2\" style=\"font-size:larger\" | " |
<< init_cap(skill_full_name(s)) << endl; | << init_cap(skill_full_name(s)) << endl; | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "! Max !! Role" << endl; | cout << "! Max !! Role" << endl; | ||
− | + | ||
for (Level l = P_BASIC; l <= P_GRAND_MASTER; l++) { | for (Level l = P_BASIC; l <= P_GRAND_MASTER; l++) { | ||
if (!some_role_has_level(s, l)) { continue; } | if (!some_role_has_level(s, l)) { continue; } | ||
− | + | ||
cout << "|-" << endl; | cout << "|-" << endl; | ||
cout << "| " << level_full(l) << endl; | cout << "| " << level_full(l) << endl; | ||
− | + | ||
cout << "|" << endl; | cout << "|" << endl; | ||
− | + | ||
vector<string> roles; | vector<string> roles; | ||
push_matching_roles(s, l, roles); | push_matching_roles(s, l, roles); | ||
print_matching_roles(roles); | print_matching_roles(roles); | ||
} | } | ||
− | + | ||
cout << "|}"; | cout << "|}"; | ||
− | + | ||
string index(init_cap(skill_full_name(s))); | string index(init_cap(skill_full_name(s))); | ||
print_noinclude("Skill-specific skill tables", index.c_str()); | print_noinclude("Skill-specific skill tables", index.c_str()); | ||
} | } | ||
− | + | ||
void | void | ||
print_usage(const char *name) { | print_usage(const char *name) { | ||
cout << "Usage:" << endl << endl; | cout << "Usage:" << endl << endl; | ||
− | + | ||
cout << " " << name << " weapon|combat|spell" << endl; | cout << " " << name << " weapon|combat|spell" << endl; | ||
cout << " ==> overall weapon/combat/spell matrix" << endl << endl; | cout << " ==> overall weapon/combat/spell matrix" << endl << endl; | ||
− | + | ||
cout << " " << name << " Role" << endl; | cout << " " << name << " Role" << endl; | ||
cout << " ==> role-specific table (type A)" << endl << endl; | cout << " ==> role-specific table (type A)" << endl << endl; | ||
− | + | ||
cout << " " << name << " Rol" << endl; | cout << " " << name << " Rol" << endl; | ||
cout << " ==> role-specific table (type B)" << endl << endl; | cout << " ==> role-specific table (type B)" << endl << endl; | ||
− | + | ||
cout << " " << name << " \"skill\"" << endl; | cout << " " << name << " \"skill\"" << endl; | ||
cout << " ==> skill-specific table" << endl; | cout << " ==> skill-specific table" << endl; | ||
Line 537: | Line 557: | ||
if (argc == 2) { | if (argc == 2) { | ||
const string arg(argv[1]); | const string arg(argv[1]); | ||
− | + | ||
if (arg == "weapon") { | if (arg == "weapon") { | ||
do_skill_table("Weapon", P_FIRST_WEAPON, P_LAST_WEAPON); | do_skill_table("Weapon", P_FIRST_WEAPON, P_LAST_WEAPON); |
Revision as of 16:58, 12 November 2010
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[]
.
This program is designed to work with NetHack 3.4.3. If a new version is released, the program might need changes, and the generated tables might need to be re-generated.
To compile the program, you need a C++ compiler, such as g++. Assuming you've saved the code as skillgen.cpp, you can compile it with
g++ -o skillgen skillgen.c
This page may need to be updated for the current version of NetHack.
It may contain text specific to NetHack 3.4.3. Information on this page may be out of date.
Editors: After reviewing this page and making necessary edits, please change the {{nethack-343}} tag to the current version's tag or {{noversion}} as appropriate.
The code for skillgen.cpp:
#include <string> #include <iostream> #include <cctype> #include <vector> #include <stdlib.h> 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 "???"; } } const char * level_span_class(const Level &l) { switch (l) { case P_ISRESTRICTED: return "class=\"restricted\""; case P_BASIC: return "class=\"basic\""; case P_SKILLED: return "class=\"skilled\""; case P_EXPERT: return "class=\"expert\""; case P_MASTER: return "class=\"master\""; case P_GRAND_MASTER: return "class=\"grandmaster\""; default: return "class=\"unknown_skill\""; } } #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_role_skill_level_span_class(const Role &r, const Skill &s) { print_role_skill_level(r, s, level_span_class); } 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 [[NetHackWiki:Skill table generator]]. " "Instead of editing this page, edit that program, and re-generate " "this page." << endl << endl << "{{nethack-343}}" << 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 " << index << "-skilltable\"" << 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 << "\n|"; print_role_skill_level_span_class(r, s); cout << "| "; print_role_skill_level_char(r, s); } cout << endl; } cout << "|}\n"; 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]); } }