Author Topic: Smaug-to-DS conversion system  (Read 3780 times)

Offline cratylus

  • Your favorite and best
  • Administrator
  • ***
  • Posts: 1024
  • Cratylus@Dead Souls <ds> np
    • View Profile
    • About Cratylus
Smaug-to-DS conversion system
« on: March 24, 2007, 02:23:58 pm »
I started work last night on a Smaug area conversion
system, and I think I've made decent progress in just
a couple of hours.

I've coded an object that will take an area file
and a domain directory as arguments, then translates
Smaug gibberish into DS LPC.

For now it's just a portable object. You can
put it into /secure/obj/thing.c and then clone it.
Eventually I'll make it a command.


As an example, if you download Rolindar's "Queen of the Demonweb Pits"
area from http://asj.mudmagic.com/areas/viewforum.php?f=3 into
/open/demonweb_177.are , you would then issue these commands:

domaincreate demonweb
convert /open/demonweb_177.are demonweb

And that's it. Presto. You have a bunch of rooms and
objects and NPC's in your new domain, as defined in that
area file.

Now, I've only just started, so not everything works
100% yet. Some of the rooms seem to have faulty exits
or recursive exits. The npc's are all human and lack
the fancy mobprogs and such. But it's a start, and it
should make the process of migrating from Smaug mud
to DS an order of magnitude less tedious.

Eventually I want this conversion system to accommodate
Diku derivatives of different flavors, and to handle
the complicated chats and combats and such.

I'm providing this rough draft as a way of sharing
the progress already done, and to invite comment from
those who might have already done something similar,
and have a suggestion on going forward.

This code will work on Dead Souls 2.4.1 and higher.

-Crat

Code: [Select]
#include <lib.h>
#include <vendor_types.h>
inherit LIB_ITEM;

string original, digested;
mapping AreaMap = ([]);
mapping RawMap = ([]);
mapping Genders = ([ 0 : "neutral", 1 : "male", 2 : "female" ]);
mapping Directions = ([ 0 : "north", 1 : "east", 2 : "south",
  3 : "west", 4 : "up", 5 : "down", 6 : "northeast", 7 : "northwest",
  8 : "southeast", 9 : "southwest", 10 : "somewhere" ]);
mapping Types = ([ 1 : "LIB_ITEM", 2 : "LIB_ITEM", 3 : "LIB_ITEM", 4 : "LIB_ITEM",
  5 : "LIB_ITEM", 6 : "LIB_ITEM", 7 : "LIB_ITEM", 8 : "LIB_ITEM", 9 : "LIB_ARMOR", 10 : "LIB_POTION",
  11 : "LIB_ITEM", 12 : "LIB_BED", 13 : "LIB_ITEM", 14 : "LIB_ITEM", 15 : "LIB_STORAGE",
  16 : "LIB_ITEM", 17 : "LIB_MEAL", 18 : "LIB_ITEM", 19 : "LIB_MEAL", 20 : "LIB_PILE",
  21 : "LIB_ITEM", 22 : "LIB_ITEM", 23 : "LIB_ITEM", 24 : "LIB_ITEM", 25 : "LIB_ITEM",
  26 : "LIB_ITEM", 44 : "LIB_ITEM" ]);
string gdirection, cle, val;
int item_type, extra_flags, wear_flags;
int tmp1, tmp2, tmp3;
mixed value_1, value_2, value_3, value_4, value_5;
int weight, cost, cost_per_day;
int lock, key, room, direction;
int ok, ok2;

void create(){
    ::create();
    SetKeyName("generic thing");
    SetId( ({"thing","item","thang","dingus"}) );
    SetAdjectives( ({"generic","sample","template"}) );
    SetShort("a generic thing");
    SetLong("This is an object of indeterminate nature and proportions.");
    SetMass(200);
    SetDollarCost(10);
    SetVendorType(VT_TREASURE);
}
void init(){
    ::init();
    add_action("ConvertArea","convert");
    add_action("Report","report");
}

int Report(string str){
    print_long_string(this_player(),"vnums: "+item_list(keys(AreaMap)),1);
    if(str == "both" || str == "area") print_long_string(this_player(),"%^RED%^AreaMap: "+identify(AreaMap),1);
    if(str == "both" || str == "raw") print_long_string(this_player(),"%^GREEN%^RAWMap: "+identify(RawMap),1);
    if(sscanf(str,"%*d")) this_object()->DisplayVnum(str);
    return 1;
}

int DisplayVnum(string str){
    if(!str || !AreaMap[str]){
write("No such vnum in this area.");
return 1;
    }
    print_long_string(this_player(),"vnum "+str+":\n"+identify(AreaMap[str]),1);
    return 1;
}

int ConvertArea(string arg){
    string tmp, str, name, prefix;
    int i;
    string *rooms_arr;
    string *obs_arr;
    string *delimiters = ({ "#AREA", "#VERSION", "#AUTHOR", "#RANGES", "#RESETMSG",
      "#FLAGS", "#ECONOMY", "#CLIMATE", "#HELPS", "#MOBILES", "#OBJECTS",
      "#ROOMS", "#RESETS", "#SHOPS", "#REPAIRS", "#SPECIALS", "#$" });
    string *new_delimiters = ({});
    string *segmented = ({});

    if(!arg || sscanf(arg,"%s %s",str, name) != 2){
write("convert FILE AREA");
return 1;
    }

    if(!str || !file_exists(str)){
write("No such area file exists.");
return 1;
    }
    original = read_file(str);
    digested = original;
    foreach(string element in delimiters){
tmp = replace_string(element,"#","0^0");
//tc("tmp: "+tmp);
digested = replace_string(digested,element,tmp);
new_delimiters += ({ tmp });
    }

    segmented = explode(digested,"0^0");
    //print_long_string(this_player(),identify(segmented),1);

    foreach(mixed element in segmented){
string *minced = explode(element,"\n");
if(!RawMap) RawMap = ([]);
RawMap[minced[0]] = minced[1..];
    }

    /////
    // ITEMS
    /////

    tmp = implode(RawMap["OBJECTS"],"\n");
    prefix = "/domains/"+name+"/obj/";
    obs_arr = explode(tmp,"#");
    foreach(mixed block in obs_arr){
string *ob_id;
string *lines = explode(block,"\n");
string short, long, ob_name;
string header = "";
ok = 0;
//tc("block: "+block);
if(block && sizeof(lines) > 1){
    ob_id = explode(truncate(lines[1],1)," ");
    if(!sizeof(ob_id)) continue;
    ob_name = ob_id[0];
    short = truncate(lines[2],1);
    long = "";
    for(i=2;i < sizeof(lines);i++){
int num = i;
if(sscanf(lines[i],"%d %d %d %d",value_1, value_2, value_3, value_4) == 4){
    ok = 1;
}
else if(sscanf(lines[i],"%d %d %d",tmp1, tmp2, tmp3) == 3){
    if(ok){
weight = tmp1;
cost = tmp2;
cost_per_day = tmp3;
    }
    else {
item_type = tmp1;
extra_flags = tmp2;
wear_flags = tmp3;
    }
}

if(lines[i] == "E"){
    for(num = i+2; num < sizeof(lines);num++){
if(lines[num] == "~") break;
long += lines[num]+" ";
    }
    break;
}
    }
}

header += "#include <lib.h>\n\n";
header += "inherit "+Types[item_type]+";\n\n";
header += "static void create() {\n";
header += "    ::create();\n";
header += "    SetKeyName(\""+ob_name+"\");\n";
header += "    SetId( "+identify(ob_id)+" );\n";
header += "    SetShort(\""+short+"\");\n";
header += "    SetLong(\""+long+"\");\n";
header += "    SetMass("+weight+");\n";
header += "    SetBaseCost("+cost+");\n";
header += "}\nvoid init(){\n::init();\n}\n";

//print_long_string(this_player(), header, 1);
//tc("file above was: "+prefix+lines[0]+"_"+ob_name+".c");
if(directory_exists(truncate(prefix,1))){
    write_file(prefix+lines[0]+"_"+ob_name+".c",header,1);
}

if(!AreaMap) AreaMap = ([]);

if(!AreaMap[lines[0]]) AreaMap[lines[0]] =  ([ prefix+lines[0]+"_"+ob_name+".c" : header ]);
else  AreaMap[lines[0]][prefix+lines[0]+"_"+ob_name+".c"] = header;
    }

    /////
    // MOBS
    /////

    tmp = implode(RawMap["MOBILES"],"\n");
    prefix = "/domains/"+name+"/npc/";
    obs_arr = explode(tmp,"#");
    foreach(mixed block in obs_arr){
string *ob_id;
string *lines = explode(block,"\n");
string short, long, ob_name;
string header = "";
ok = 0;
ok2 = 0;
//tc("block: "+block);
if(block && sizeof(lines) > 1){
    ob_id = explode(truncate(lines[1],1)," ");
    if(!sizeof(ob_id)) continue;
    ob_name = ob_id[0];
    short = truncate(lines[2],1);
    long = "";
    for(i=0;i < sizeof(lines);i++){
int num = i;
if(!ok && sscanf(lines[i],"%d %d %d %s %s",value_1, value_2, value_3, value_4, value_5) == 5){
    ok =1;
}
if( ok == 1 && sizeof(explode(lines[i]," ")) == 3 && sscanf(lines[i],"%d %d %d",value_2, value_3, value_4) == 3){
    //tc("Gender: "+value_4);
    ok++;
}
if(!ok2 && i > 3){
    if(i > 4 && lines[i] == "~"){
ok2 = 1;
continue;
    }
    if(lines[i] != "~") long += lines[i]+" ";
}
    }

    header += "#include <lib.h>\n\n";
    header += "inherit LIB_SENTIENT;\n\n";
    header += "static void create(){\n";
    header += "    ::create();\n";
    header += "    SetKeyName(\""+ob_name+"\");\n";
    header += "    SetId( "+identify(ob_id)+" );\n";
    header += "    SetShort(\""+short+"\");\n";
    header += "    SetLong(\""+long+"\");\n";
    header += "    SetLevel("+value_1+");\n";
    header += "    SetRace(\"human\");\n";
    header += "    SetNoCondition(1);\n";
    header += "    SetGender(\""+Genders[value_4]+"\");\n";
    header += "}\nvoid init(){\n::init();\n}\n";

    //print_long_string(this_player(), header, 1);
    //tc("file above was: "+prefix+lines[0]+"_"+ob_name+".c");
    if(directory_exists(truncate(prefix,1))){
write_file(prefix+lines[0]+"_"+ob_name+".c",header,1);
    }

    if(!AreaMap) AreaMap = ([]);

    if(!AreaMap[lines[0]]) AreaMap[lines[0]] =  ([ prefix+lines[0]+"_"+ob_name+".c" : header ]);
    else  AreaMap[lines[0]][prefix+lines[0]+"_"+ob_name+".c"] = header;
}
    }
    /////
    // ROOMS
    /////

    tmp = implode(RawMap["ROOMS"],"\n");
    prefix = "/domains/"+name+"/room/";
    rooms_arr = explode(tmp,"#");
    foreach(mixed block in rooms_arr){
string *lines = explode(block,"\n");
string short, long;
string header = "#include <lib.h>\n";
header += "#include <rooms.h>\n\n";
header += "inherit LIB_ROOM;\n\n";
header += "void create() {\n";
header += "    room::create();\n";
header += "    SetClimate(\"indoors\");\n";
header += "    SetAmbientLight(30);\n";


short = truncate(lines[1],1);
long = "";
for(i=2;i < sizeof(lines);i++){
    if(lines[i] == "~") break;
    long += lines[i]+" ";
}

header += "    SetShort(\""+short+"\");\n";
header += "    SetLong(\""+long+"\");\n";
header += "    SetExits( ([\n";

for(i=i;i < sizeof(lines);i++){
    //int lock, key, room, direction;
    lock = key = room = direction = 0;
    if(lines[i] == "S") break;
    if(sscanf(lines[i],"%d %d %d",lock, key, room) == 3){
if(sscanf(lines[i+1],"D%d",direction)){
    if(room == 0){
gdirection = Directions[direction];
continue;
    }
    else header += "    \""+Directions[direction]+"\" : \""+prefix+room+"\",\n";
}
else if(sizeof(gdirection) > 1){
    if(room != 0) header += "    \""+gdirection+"\" : \""+prefix+room+"\",\n";
    gdirection = "";
}
    }
}

header += "    ]) );\n";
header += "    SetInventory( ([\n";
if(AreaMap && AreaMap[lines[0]])
    foreach(cle, val in AreaMap[lines[0]]){
    if(!grepp(val,"LIB_ROOM")){
header += "        \""+cle+"\" : 1,\n";
    }
}
header += "    ]) );\n";
header += "}\n";
header += "void init(){\n";
header += "   ::init();\n";
header += "}\n";

//print_long_string(this_player(),header,1);
//tc("file above was: "+prefix+lines[0]+".c");
if(directory_exists(truncate(prefix,1))){
    write_file(prefix+lines[0]+".c",header,1);
}

if(!AreaMap) AreaMap = ([]);

if(!AreaMap[lines[0]]) AreaMap[lines[0]] =  ([ prefix+lines[0]+".c" : header ]);
else  AreaMap[lines[0]][prefix+lines[0]+".c"] = header;
    }

    return 1;
}


Offline daelaskai

  • BFF
  • ***
  • Posts: 174
    • View Profile
Re: Smaug-to-DS conversion system
« Reply #1 on: March 24, 2007, 07:59:14 pm »
Very interesting.  I'd think this will open a lot of doors especially to people who are used to smaug coding.  Great work, Cratylus :)

Daelas

Offline Draun

  • Acquaintance
  • *
  • Posts: 4
    • View Profile
Re: Smaug-to-DS conversion system
« Reply #2 on: March 06, 2008, 02:43:50 pm »
Has this made any more progress?  I'm trying to switch from diku-type muds to a LPmud flavor, and this would be a great way to move over some areas that I had made years ago.

Offline cratylus

  • Your favorite and best
  • Administrator
  • ***
  • Posts: 1024
  • Cratylus@Dead Souls <ds> np
    • View Profile
    • About Cratylus
Re: Smaug-to-DS conversion system
« Reply #3 on: March 06, 2008, 03:26:40 pm »
Yep, I made some improvements to the conversion system. It's now a command
rather than an object. I haven't polished it to "It works GREAT", but it's
polished to "It works pretty ok".

It'll never translate with 100% fidelity to the original, but it's
a definite aid in cutting down the amount of work needed
to port areas.

I really can't tell you how it'll work with your stuff. The
only way to know is to download the latest version
of DS ( http://dead-souls.net/code/alpha/ )and give the sconv command a try.

-Crat

Offline quixadhal

  • BFF
  • ***
  • Posts: 642
    • View Profile
    • WileyMUD
Re: Smaug-to-DS conversion system
« Reply #4 on: March 06, 2008, 07:08:46 pm »
Just in case it might prove semi-useful, or at least amusing, feel free to take a peek at the convert subdirectory in my old WileyMUD archive.

The code reads in my own mud's (custom) format, but of particular interest to you might be the consistency check routines.  It's unfinished, but if you can get anything useful out of it, go for it!

Offline Draun

  • Acquaintance
  • *
  • Posts: 4
    • View Profile
Re: Smaug-to-DS conversion system
« Reply #5 on: March 07, 2008, 10:15:57 pm »
That's funny.  I'm using the alpha version and didn't know that was there.

The initial code was a bit on the crazy side.  It would make two or three rooms connected and then load in objects in the place of mobs for some rooms.

Offline cratylus

  • Your favorite and best
  • Administrator
  • ***
  • Posts: 1024
  • Cratylus@Dead Souls <ds> np
    • View Profile
    • About Cratylus
Re: Smaug-to-DS conversion system
« Reply #6 on: March 08, 2008, 02:37:16 pm »
Yeah I just tried it and realized I goofed...the version of sconv currently in
the distribution is broken and makes inconsistent exits.

The next alpha release should be out this weekend and will have a
version of sconv that behaves more sanely, as well as "cconv" which
converts from CWG format (a variety of Circle).

-Crat

Offline Draun

  • Acquaintance
  • *
  • Posts: 4
    • View Profile
Re: Smaug-to-DS conversion system
« Reply #7 on: March 10, 2008, 07:28:07 pm »
Do you know which version of CWG?  I think there are three or four different flavors that they have.

That's amazing how quickly you can put that together, btw.

Offline cratylus

  • Your favorite and best
  • Administrator
  • ***
  • Posts: 1024
  • Cratylus@Dead Souls <ds> np
    • View Profile
    • About Cratylus
Re: Smaug-to-DS conversion system
« Reply #8 on: March 11, 2008, 08:40:27 am »
Quote
Do you know which version of CWG?  I think there are three or four different flavors that they have.

That's amazing how quickly you can put that together, btw.

Actually this was done a while back, I just somehow neglected to
put it into the distribution. DS2.7a13 now has three conversion commands:

sconv for Smaug
cwgconv for CWG
cconv for Circle

cconv right now only does rooms, I think...I haven't got
around to finessing it.

As to the version of CWG, I'm not sure. I developed
cwgconv with help from Sryth @ Afterthoughts...hopefully
he'll notice this post and pipe up with version info.

-Crat