Difference between revisions of "NetHackWiki:Skill table generator"
Jump to navigation
Jump to search
(now supports skill-specific and role-specific tables) |
(now with two different role-specific table formats) |
||
Line 1: | Line 1: | ||
− | Here's the program I used to generate [[Template:Weapon skill table]], [[Template:Combat skill table]], and [[Template:Spell skill table]]. <code>u_init_snippet.inc</code> should be the <code>struct def_skill</code> definitions in [[u_init.c]], from <code>Skill_A[]</code> to <code>Skill_W[]</code>. | + | Here's the program I used to generate [[Template:Weapon skill table]], [[Template:Combat skill table]], and [[Template:Spell skill table]]. -- [[User:Killian|Killian]] 07:39, 4 November 2006 (UTC) |
+ | |||
+ | <code>modified_skills.h</code> should be a copy of [[skills.h]], modified so that <code>P_BARE_HANDS</code> and <code>P_MARTIAL_ARTS</code> have separate numbers. | ||
+ | |||
+ | <code>u_init_snippet.inc</code> should be the <code>struct def_skill</code> definitions in [[u_init.c]], from <code>Skill_A[]</code> to <code>Skill_W[]</code>. | ||
<pre> | <pre> | ||
Line 5: | Line 9: | ||
#include <iostream> | #include <iostream> | ||
#include <cctype> | #include <cctype> | ||
+ | #include <vector> | ||
using std::string; | using std::string; | ||
Line 10: | Line 15: | ||
using std::endl; | using std::endl; | ||
using std::toupper; | 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 | ||
− | const | ||
− | const | ||
− | |||
const char * | const char * | ||
− | skill_raw_name(Skill s) { | + | skill_raw_name(const Skill &s) { |
switch (s) { | switch (s) { | ||
case P_DAGGER: return "dagger"; | case P_DAGGER: return "dagger"; | ||
Line 136: | Line 89: | ||
string::iterator i = s.begin(); | string::iterator i = s.begin(); | ||
− | if (i) { *i = toupper(*i); } | + | if (i != s.end()) { *i = toupper(*i); } |
return s; | return s; | ||
Line 157: | Line 110: | ||
level_char(const Level &l) { | level_char(const Level &l) { | ||
switch (l) { | switch (l) { | ||
− | case | + | case P_ISRESTRICTED: return "-"; |
case P_BASIC: return "b"; | case P_BASIC: return "b"; | ||
case P_SKILLED: return "''S''"; | case P_SKILLED: return "''S''"; | ||
Line 170: | Line 123: | ||
level_full(const Level &l) { | level_full(const Level &l) { | ||
switch (l) { | switch (l) { | ||
− | case | + | case P_ISRESTRICTED: return "''(restricted)''"; |
case P_BASIC: return "Basic"; | case P_BASIC: return "Basic"; | ||
case P_SKILLED: return "Skilled"; | case P_SKILLED: return "Skilled"; | ||
Line 180: | Line 133: | ||
} | } | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
#include "u_init_snippet.inc" | #include "u_init_snippet.inc" | ||
Line 211: | Line 151: | ||
{ "Wizard", "Wiz", Skill_W }, | { "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 | bool | ||
is_restricted(const Role &r, const Skill &s) { | 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) { | for (const def_skill *sp = r.skills; sp->skill != P_NONE; ++sp) { | ||
− | if (sp-> | + | if (sp->skmax == l) { |
− | return | + | return true; |
} | } | ||
} | } | ||
− | + | return l == P_ISRESTRICTED; | |
− | return | ||
} | } | ||
Line 237: | Line 191: | ||
void | void | ||
− | print_role_skill_level(const Role &r, const Skill &s) { | + | 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) { | for (const def_skill *sp = r.skills; sp->skill != P_NONE; ++sp) { | ||
if (sp->skill == s) { | if (sp->skill == s) { | ||
− | cout << | + | cout << stringifier(sp->skmax); |
return; | return; | ||
} | } | ||
} | } | ||
− | cout << level_char | + | 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 | void | ||
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); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
Line 274: | Line 230: | ||
"this page." | "this page." | ||
<< "</noinclude>" << endl; | << "</noinclude>" << endl; | ||
+ | } | ||
+ | |||
+ | string | ||
+ | skill_link(const Skill &s) { | ||
+ | return string("[[") + skill_full_name(s) | ||
+ | + "|" + skill_raw_name(s) + "]]"; | ||
} | } | ||
void | void | ||
print_skill_link(const Skill &s) { | print_skill_link(const Skill &s) { | ||
− | cout << | + | cout << skill_link(s); |
− | |||
} | } | ||
+ | |||
void | void | ||
Line 322: | Line 284: | ||
cout << " || "; | cout << " || "; | ||
− | + | print_role_skill_level_char(r, s); | |
} | } | ||
Line 354: | Line 316: | ||
cout << "| colspan=\"2\" align=\"center\" | ''Combat skills''" << endl; | cout << "| colspan=\"2\" align=\"center\" | ''Combat skills''" << endl; | ||
− | print_role_skills(r, | + | print_role_skills(r, P_FIRST_H_TO_H, P_LAST_H_TO_H); |
cout << "|-" << endl; | cout << "|-" << endl; | ||
Line 360: | Line 322: | ||
print_role_skills(r, P_FIRST_SPELL, P_LAST_SPELL); | print_role_skills(r, P_FIRST_SPELL, P_LAST_SPELL); | ||
+ | |||
+ | cout << "|}"; | ||
+ | |||
+ | print_noinclude(); | ||
+ | } | ||
+ | |||
+ | 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 << "|}"; | cout << "|}"; | ||
Line 397: | Line 427: | ||
void | void | ||
print_usage(const char *name) { | print_usage(const char *name) { | ||
− | cout << "Usage:" << endl; | + | cout << "Usage:" << endl << endl; |
+ | |||
cout << " " << name << " weapon|combat|spell" << endl; | cout << " " << name << " weapon|combat|spell" << endl; | ||
− | cout << " " << name << " | + | cout << " ==> overall weapon/combat/spell matrix" << endl << endl; |
− | cout << " " << name << " | + | |
+ | 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; | ||
} | } | ||
Line 411: | Line 450: | ||
do_skill_table(P_FIRST_WEAPON, P_LAST_WEAPON); | do_skill_table(P_FIRST_WEAPON, P_LAST_WEAPON); | ||
} else if (arg == "combat") { | } else if (arg == "combat") { | ||
− | do_skill_table( | + | do_skill_table(P_FIRST_H_TO_H, P_LAST_H_TO_H); |
} else if (arg == "spell") { | } else if (arg == "spell") { | ||
do_skill_table(P_FIRST_SPELL, P_LAST_SPELL); | do_skill_table(P_FIRST_SPELL, P_LAST_SPELL); | ||
Line 417: | Line 456: | ||
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 ( | + | if (arg == r.short_name) { |
do_role_skill_table(r); | do_role_skill_table(r); | ||
+ | exit(0); | ||
+ | } else if (arg == r.long_name) { | ||
+ | do_role_skill_table_2(r); | ||
exit(0); | exit(0); | ||
} | } | ||
} | } | ||
− | for (Skill s = | + | for (Skill s = 0; s < P_NUM_SKILLS; ++s) { |
if (arg == skill_raw_name(s)) { | if (arg == skill_raw_name(s)) { | ||
do_skill_role_table(s); | do_skill_role_table(s); | ||
Line 434: | Line 476: | ||
} | } | ||
} | } | ||
− | <pre> | + | </pre> |
Revision as of 07:39, 4 November 2006
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 "broad sword"; 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"); } 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(void) { 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." << "</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 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(); } 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(); } 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(); } 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 << "|}"; print_noinclude(); } 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(P_FIRST_WEAPON, P_LAST_WEAPON); } else if (arg == "combat") { do_skill_table(P_FIRST_H_TO_H, P_LAST_H_TO_H); } else if (arg == "spell") { do_skill_table(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(s); exit(0); } } print_usage(argv[0]); } } else { print_usage(argv[0]); } }