A simple mechanism to markup mud output |
A mechanism to markup mud outputIt looks a bit like HTML You are in a [fairy]huge[/fairy] cavern. [day]Shafts of light descend from an opening high in the cavern ceiling.[/day]... This implementation does support ==, && (and), || (or) logic, though it's subtle. [fairy][mage]Show to fairy mage[/mage][/fairy] --> (race == fairy && class == mage) [fairy]Show to fairy[/fairy][elf]Show to elf[/elf] --> (race == fairy || race == elf) ...but not integral value tests or intergral comparison tests. (age > 25) (level == 1) It can be easily extended to do things like that: [dwarf][age 25+]Something for old dwarves[/age][/dwarf] --> (race == dwarf && age >= 25) [level 1]Welcome newbie.[/level] --> (level == 1) [detect hidden 50]something really secret[/detect hidden] --> (skill_check("detect hidden", 50) == true) [evil]a view from the dark side[/evil] --> (alignment <= -350) I think it's a good example of creating an interface that tries its damndest to not turn builders into coders. I suspect trying to convert them often makes them unhappy and disgruntled. I don't know if that's really true or not. Ahh the power of regular expressions. |
int termwidth[] = {40,60,80}; string sex[] = {"male", "female"}; string race[] = {"human", "elf", "fairy"}; string tod[] = {"day", "night"}; |
int Termwidth[] = {40,60,80}; string Sex[] = {"male", "female"}; string Race[] = {"human", "elf", "fairy"}; string TOD[] = {"day", "night"}; |
vector<int> Termwidth; vector<string> Sex; vector<string> Race; vector<string> TOD; |
string show(string s, Player* p) { |
string show(string s, Player& p) { |
sprintf(tws,"%d",p->tw); |
string pat; for(vector<string>::iterator i = p->pf.begin(); i != p->pf.end(); i++) { pat = "\\[" + *i + "\\](.*?)\\[\\/" + *i + "\\]"; RE(pat, RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).GlobalReplace?("\\1",&str); |
for(vector<string>::iterator i = p.pf.begin(); i != p.pf.end(); i++) { RE("\\[" + *i + "\\](.*?)\\[\\/" + *i + "\\]", RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).GlobalReplace?("\\1",&str); |
pat = "\\[" + *i + "\\].*?\\[\\/" + *i + "\\]"; RE(pat, RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).GlobalReplace?("",&str); |
RE("\\[" + *i + "\\].*?\\[\\/" + *i + "\\]", RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).GlobalReplace?("",&str); |
pat = "\\S{" + string(tws) + "})(?=\\S)"; RE(pat).GlobalReplace?("\\1", &str); pat = "(.{1," + string(tws) + "})(?:\\s+|$)"; RE(pat).GlobalReplace?("\\1\n", &str); |
sprintf(tws,"%d",p.tw); RE("\\S{" + string(tws) + "})(?=\\S)").GlobalReplace?("\\1", &str); RE("(.{1," + string(tws) + "})(?:\\s+|$)").GlobalReplace?("\\1\n", &str); |
Termwidth.assign(termwidth, termwidth+3); Sex.assign(sex, sex+2); Race.assign(race, race+3); TOD.assign(tod, tod+2); Keywords.insert(Keywords.end(), Sex.begin(), Sex.end()); Keywords.insert(Keywords.end(), Race.begin(), Race.end()); Keywords.insert(Keywords.end(), TOD.begin(), TOD.end()); for(int i=0; i<5; i++) { Player* p = new Player( Sex[rand() % Sex.size()], Race[rand() % Race.size()], TOD[rand() % TOD.size()], Termwidth[rand() % Termwidth.size()] |
Keywords.insert(Keywords.end(), Sex, Sex+2); Keywords.insert(Keywords.end(), Race, Race+3); Keywords.insert(Keywords.end(), TOD, TOD+2); for(int i=0; i<10; i++) { Player p( Sex[rand() % 2], Race[rand() % 3], TOD[rand() % 2], Termwidth[rand() % 3] |
cout << "Sex:" << p->sex << " Race:" << p->race << " TOD:" << p->tod << " TW:" << p->tw << endl; |
cout << "Sex:" << p.sex << " Race:" << p.race << " TOD:" << p.tod << " TW:" << p.tw << endl; |
It looks a bit like HTML
You are in a [fairy]huge[/fairy] cavern. [day]Shafts of light descend from an opening high in the cavern ceiling.[/day]...
This implementation does support ==, && (and), || (or) logic, though it's subtle.
[fairy][mage]Show to fairy mage[/mage][/fairy] --> (race == fairy && class == mage)
[fairy]Show to fairy[/fairy][elf]Show to elf[/elf] --> (race == fairy || race == elf)
...but not integral value tests or intergral comparison tests.
(age > 25)
(level == 1)
It can be easily extended to do things like that:
[dwarf][age 25+]Something for old dwarves[/age][/dwarf] --> (race == dwarf && age >= 25)
[level 1]Welcome newbie.[/level] --> (level == 1)
[detect hidden 50]something really secret[/detect hidden] --> (skill_check("detect hidden", 50) == true)
[evil]a view from the dark side[/evil] --> (alignment <= -350)
I think it's a good example of creating an interface that tries its damndest to not turn builders into coders. I suspect trying to convert them often makes them unhappy and disgruntled. I don't know if that's really true or not.
Ahh the power of regular expressions.
# a simple dynamic description markup processor - Ruby version require 'ostruct'; Termwidth=[40,60,80];Sex=%w(male female);Race=%w(human elf fairy) TOD = %w(day night);Keywords = Sex+Race+TOD Desc=<<-EOD You are in a [fairy]huge[/fairy] cavern. [day]Shafts of light descend from an opening high in the cavern ceiling.[/day] Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a [elf]foul-smelling[/elf][fairy]disgusting[/fairy][human]hideous[/human] hobbit. [female]You shriek hysterically.[/female] EOD def show(s, p) pf=[];pf<<p.sex<<p.race<<p.tod;str=s.dup pf.each {|k| str.gsub!(/\[#{k}\](.*?)\[\/#{k}\]/mi,'\1')} Keywords.each {|k| str.gsub!(/\[#{k}\].*?\[\/#{k}\]/mi,'')} str.gsub!(/\n/,' ');str.squeeze!(' ') str.gsub!(/(\S{#{p.tw}})(?=\S)/,'\1 ') str.scan(/(.{1,#{p.tw}})(?:\s+|$)/).flatten.join("\n") end def mockplayer p = OpenStruct.new p.sex=Sex[rand(Sex.size)] p.race=Race[rand(Race.size)] p.tod=TOD[rand(TOD.size)] p.tw=Termwidth[rand(Termwidth.size)] p end 5.times do p=mockplayer puts "Sex:#{p.sex} Race:#{p.race} TOD:#{p.tod} TW:#{p.tw}" puts show(Desc,p) puts end
$ ruby dyndesc.rb Sex:female Race:fairy TOD:day TW:80 You are in a huge cavern. Shafts of light descend from an opening high in the cavern ceiling. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a disgusting hobbit. You shriek hysterically. Sex:male Race:fairy TOD:night TW:40 You are in a huge cavern. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a disgusting hobbit. Sex:female Race:fairy TOD:night TW:40 You are in a huge cavern. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a disgusting hobbit. You shriek hysterically. Sex:female Race:human TOD:day TW:60 You are in a cavern. Shafts of light descend from an opening high in the cavern ceiling. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a hideous hobbit. You shriek hysterically. Sex:male Race:fairy TOD:night TW:40 You are in a huge cavern. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a disgusting hobbit.
// a simple dynamic description markup processor - C++ version #include <vector> #include <string> #include <iostream> #include <pcrecpp.h> using namespace std; using namespace pcrecpp; int Termwidth[] = {40,60,80}; string Sex[] = {"male", "female"}; string Race[] = {"human", "elf", "fairy"}; string TOD[] = {"day", "night"}; string Desc = "You are in a [fairy]huge[/fairy] cavern. [day]Shafts of light descend from " "an opening high in the cavern ceiling.[/day] Writhing on the cavern floor " "is a decaying corpse writhing with maggots. Feasting on the corpse is a " "[elf]foul-smelling[/elf][fairy]disgusting[/fairy][human]hideous[/human] " "hobbit. [female]You shriek hysterically.[/female] "; vector<string> Keywords; class Player { public: int tw; string sex; string race; string tod; vector<string> pf; Player(string _sex,string _race,string _tod, int _tw) : sex(_sex), race(_race), tod(_tod), tw(_tw) { pf.insert(pf.end(),sex); pf.insert(pf.end(),race); pf.insert(pf.end(),tod); } }; string show(string s, Player& p) { char tws[10]; string str(s); for(vector<string>::iterator i = p.pf.begin(); i != p.pf.end(); i++) { RE("\\[" + *i + "\\](.*?)\\[\\/" + *i + "\\]", RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).GlobalReplace("\\1",&str); } for(vector<string>::iterator i = Keywords.begin(); i != Keywords.end(); i++) { RE("\\[" + *i + "\\].*?\\[\\/" + *i + "\\]", RE_Options(PCRE_CASELESS|PCRE_MULTILINE)).GlobalReplace("",&str); } RE("\\n").GlobalReplace(" ", &str); RE(" ").GlobalReplace(" ", &str); sprintf(tws,"%d",p.tw); RE("\\S{" + string(tws) + "})(?=\\S)").GlobalReplace("\\1", &str); RE("(.{1," + string(tws) + "})(?:\\s+|$)").GlobalReplace("\\1\n", &str); return str; } int main(int argc, char** argv) { Keywords.insert(Keywords.end(), Sex, Sex+2); Keywords.insert(Keywords.end(), Race, Race+3); Keywords.insert(Keywords.end(), TOD, TOD+2); for(int i=0; i<10; i++) { Player p( Sex[rand() % 2], Race[rand() % 3], TOD[rand() % 2], Termwidth[rand() % 3] ); cout << "Sex:" << p.sex << " Race:" << p.race << " TOD:" << p.tod << " TW:" << p.tw << endl; cout << show(Desc,p) << endl; cout << endl; } return 0; }
$ g++ dyndesc.cpp -lpcrecpp $ ./a Sex:male Race:human TOD:night TW:40 You are in a cavern. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a hideous hobbit. Sex:male Race:human TOD:day TW:80 You are in a cavern. Shafts of light descend from an opening high in the cavern ceiling. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a hideous hobbit. Sex:female Race:elf TOD:day TW:40 You are in a cavern. Shafts of light descend from an opening high in the cavern ceiling. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a foul-smelling hobbit. You shriek hysterically. Sex:male Race:fairy TOD:night TW:80 You are in a huge cavern. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a disgusting hobbit. Sex:female Race:human TOD:day TW:80 You are in a cavern. Shafts of light descend from an opening high in the cavern ceiling. Writhing on the cavern floor is a decaying corpse writhing with maggots. Feasting on the corpse is a hideous hobbit. You shriek hysterically.