| // MorgenGrauen MUDlib |
| // |
| // - Prototypen und Properties in thing/material.h |
| // - Liste in materials.h |
| // |
| // TODO: properties.h um materials.h erweitern |
| // |
| // - implizite Gruppenzuordnung entfernen, da jetzt explizit in |
| // Definitionsdateien vorhanden |
| // - Materialdoku ueberarbeiten, dabei Hinweis auf nicht mehr implizite |
| // Gruppenzuordnung |
| // /p/daemon/materialdb.c -- Materialdatenbank |
| // |
| // $Id: materialdb.c 8755 2014-04-26 13:13:40Z Zesstra $ |
| |
| #pragma strong_types |
| #pragma no_clone |
| #pragma no_inherit |
| #pragma no_shadow |
| #pragma pedantic |
| |
| // Die Propertydefinition reinholen |
| #include <language.h> |
| #include <thing/description.h> |
| // Materialliste nicht mit reinziehen |
| #define _SKIP_MATERIALS_ |
| #include <thing/material.h> |
| #include <player/description.h> |
| #include <rtlimits.h> |
| |
| // Basisverzeichnis der Materialien |
| #define MAT_DIR "/doc/materials" |
| |
| // Ausgabeverzeichnis fuer Doku |
| #define DOC_DIR(x) ("/doc/materials/"+x) |
| |
| // Dateiname des Headers mit Materialdefinitionen |
| #define HEADERFILE "/sys/materials.h" |
| |
| // Savefile. |
| #define SAVEFILE DOC_DIR("materialdb") |
| |
| // Rein intern verwendete Namen |
| #define P_RECOC "recognizability" |
| #define P_ID "id" |
| #define P_DEFSTR "defstr" |
| #define P_MEMBERS "members" |
| #define P_MG_FRACTIONS "mg_fractions" |
| |
| #define LOG_ERROR(x) if(find_player("raschaua")&&find_player("raschaua")->QueryProp("mdb-debug"))tell_object(find_player("raschaua"),"MDB-Error:"+x) |
| #define LOG_WARN(x) if(find_player("raschaua")&&find_player("raschaua")->QueryProp("mdb-debug"))tell_object(find_player("raschaua"),"MDB-Warn:"+x) |
| |
| // Prototypes: |
| // (Liefert den Anteil der Materialgruppe grp an mats) |
| int MaterialGroup(mapping mats, string grp); |
| // Konvertiert eine Liste von Materialien zu ihren Namen, dabei wird die |
| // Erkennungsfaehigkeit beruecksichtigt und evtl. falsch erkannt |
| varargs string ConvMaterialList(mixed mats, int casus, mixed idinf); |
| varargs string MaterialName(string mat, int casus, mixed idinf); |
| // Gibt den Namen einer Materialgruppe zurueck |
| string GroupName(string grp); |
| // Gibt alle Materialien zurueck |
| string *AllMaterials(); |
| // Gibt alle Gruppen zurueck |
| string *AllGroups(); |
| // Gibt alle Gruppen zurueck, in denen mat enthalten ist |
| string *GetMatMembership(string mat); |
| // Gibt alle Materialien zurueck, die in grp enthalten sind |
| string *GetGroupMembers(string grp); |
| // Erneuert die Materialien durch Scannen des Materialverzeichnisses |
| void Update(); |
| // generiert Headerfile aus den Daten |
| varargs void GenHeaderFile(string fn); |
| |
| mapping materials; |
| mapping material_groups; |
| private status initialized; |
| mapping old_mat_keys; // Alter Materialkey -> neuer Key (Kompatibilitaet) |
| nosave mapping new_materials; // Materialien waehrend des Scannens |
| nosave mapping new_material_groups; // Materialgruppen waehrend des Scannens |
| private nosave status isScanning; |
| private nosave int updateTicks; |
| |
| void create() { |
| seteuid(getuid()); |
| // Savefile einlesen, falls moeglich, damit die DB direkt initialisert ist, |
| // wenn auch ggf. mit alten Daten. |
| restore_object(SAVEFILE); |
| if (initialized) { |
| // falls erfolgreich, direkt Header fuer die Mudlib schreiben |
| GenHeaderFile(); |
| } |
| // jetzt Update der Daten durchfuehren. |
| Update(); |
| } |
| |
| //==================== Umwandeln der Strings aus der thing/material.h |
| private string getMatId(string key) { |
| // Alte Bezeichner umwandeln |
| if (!member(materials, key)) |
| key = old_mat_keys[key]; |
| return key; |
| } |
| private string getMatGroupId(string key) { |
| // Alte Bezeichner umwandeln |
| if (!member(material_groups, key)) |
| key = "MATGROUP_"+upperstring(key[3..]); |
| return key; |
| } |
| private string matKey2Defstr(string key, mapping mats) { |
| string id; |
| if (member(mats[key], P_DEFSTR)) |
| id = mats[key][P_DEFSTR]; |
| else |
| id = key; |
| return id; |
| } |
| private string groupKey2Defstr(string key) { |
| if (sizeof(key) > 9) |
| key = "mg_"+lowerstring(key[9..]); |
| else |
| key = ""; |
| return key; |
| } |
| |
| //==================== Schnittstellenfunktionen zur Verwendung der DB |
| varargs string MaterialName(string mat, int casus, mixed idinf) { |
| if (initialized) { |
| string *names; |
| mapping props; |
| mixed *dif; |
| // Anpassen der Materialid |
| mat = getMatId(mat); |
| |
| if (!mappingp(props=materials[mat])) |
| props=([]); |
| |
| // Je nach Koennen des Spielers kann man das exakte Material |
| // mehr oder weniger gut erkennen: |
| if (pointerp(dif=props[P_RECOC]) |
| && (!intp(idinf)||idinf<100) ) { // 100=exakte Erkennung |
| int i, n, recval; |
| mixed *grps, tmp, x; |
| |
| recval=0; |
| grps=props[P_MG_FRACTIONS]; |
| if (!pointerp(idinf)) |
| idinf=({idinf}); |
| |
| // Zunaechst die Faehigkeit des Spielers (da koennen noch |
| // Gildenfaehigkeiten hinzu kommen) ermitteln, dieses |
| // Material zu erkennen: |
| i=sizeof(idinf); |
| while(i--) { |
| tmp=idinf[i]; |
| if (objectp(tmp)) // Diese Property ist hauptsaechlich fuer Rassen: |
| tmp=tmp->QueryProp(P_MATERIAL_KNOWLEDGE); |
| if (intp(tmp)) { |
| recval+=tmp; // Allgemeine Erkennungsfaehigkeit |
| break; |
| } |
| if (closurep(tmp) && intp(x=funcall(tmp,mat,grps))) { |
| recval+=x; |
| break; // Closures koennen immer nuetzlich sein :) |
| } |
| if (mappingp(tmp)) { |
| int j; |
| if ((x=tmp[mat]) && intp(x)){ |
| // Erkennung von speziell diesem Material |
| recval+=x; |
| break; |
| } |
| // Erkennung von Gruppen |
| j=sizeof(grps); |
| while(j--) |
| if((x=tmp[grps[j]]) && intp(x)) |
| recval+=x; |
| if (pointerp(tmp=tmp[MATERIAL_SYMMETRIC_RECOGNIZABILITY])) { |
| for (j=sizeof(tmp)-2;j>=0;j-=2) { |
| if (!intp(x=tmp[j+1])) |
| raise_error("materialdb: illegal sym.recoc. format\n"); |
| if (props[tmp[j]]) |
| recval+=x; |
| else // bei passenden Gruppen +, bei anderen - |
| recval-=x; |
| } |
| } |
| } |
| } |
| |
| // Jetzt wird ermittelt, ob vielleicht eine ungenauere |
| // Beschreibung gegeben werden soll: |
| x=dif[0]; |
| n = sizeof(dif)-1; |
| for (i=2;i<=n;i+=2) { |
| if (recval>=dif[i-1]) |
| x=dif[i]; |
| } |
| // Wenn die Faehigkeiten des Spielers nicht fuer den echten Klarnamen |
| // ausreichen, gib die Alternative zurueck: |
| if (x!=mat) |
| return MaterialName(x, casus, 100); |
| } |
| |
| if (!pointerp(names=props[P_NAME]) || sizeof(names)<4) |
| names=({"unbekanntes Material", "unbekannten Materials", |
| "unbekanntem Material", "unbekannten Material"}); |
| if (casus<0 || casus>3) |
| casus=0; |
| return names[casus]; |
| } |
| } |
| |
| varargs string ConvMaterialList(mixed mats, int casus, mixed idinf) { |
| if (initialized) { |
| string *ms,ml; |
| int i; |
| |
| ml=""; |
| if (mappingp(mats)) |
| ms=m_indices(mats); |
| else if (stringp(mats)) |
| ms=({mats}); |
| else if (pointerp(mats)) |
| ms=mats; |
| else |
| ms=({}); |
| i=sizeof(ms); |
| while(i) { |
| ml+=MaterialName(ms[--i],casus,idinf); |
| if (i) |
| ml+=((i>1)?", ":" und "); |
| } |
| return ml; |
| } |
| } |
| |
| int MaterialGroup(mapping mats, string grp) { |
| if (initialized) { |
| string *ms; |
| int i,res; |
| |
| res=0; |
| if (!mappingp(mats) || !stringp(grp)) |
| return res; |
| ms=m_indices(mats); |
| i=sizeof(ms); |
| while(i--) { |
| string mat; |
| mapping props; |
| mat=ms[i]; |
| if (mappingp(props=materials[getMatId(mat)])) |
| res+=(mats[mat]*props[P_MG_FRACTIONS][getMatGroupId(grp)])/100; |
| } |
| if (res<-100) // Vielleicht noch Antimaterie zulassen |
| res=-100; // (noch nicht sicher ob das so bleiben wird oder 0 sein wird) |
| if (res>100) |
| res=100; |
| return res; |
| } |
| } |
| |
| string *AllMaterials() { |
| if (initialized) { |
| // Aus Kompatibilitaetsgruenden die alten Schluessel (#define-String) |
| // zurueckgeben |
| return m_indices(old_mat_keys); |
| } |
| return 0; |
| } |
| |
| string *AllGroups() { |
| if (initialized) { |
| // Aus Kompatibilitaetsgruenden die alten Schluessel (#define-String) |
| // zurueckgeben |
| return map(m_indices(material_groups), #'groupKey2Defstr); |
| } |
| return 0; |
| } |
| |
| string *GetMatMembership(string mat) { |
| if (initialized) { |
| mapping props; |
| // Anpassen der Materialid |
| mat = getMatId(mat); |
| |
| if (!mappingp(props=materials[mat])) |
| return ({}); |
| return map(m_indices(props[P_MG_FRACTIONS]), #'groupKey2Defstr); |
| } |
| return 0; |
| } |
| |
| string *GetGroupMembers(string grp) { |
| if (initialized) { |
| string *mats; |
| // Anpassen der Materialid |
| grp = getMatGroupId(grp); |
| if (!member(material_groups, grp) || |
| !pointerp(mats=material_groups[grp][P_MEMBERS])) |
| return ({}); |
| return map(mats, #'matKey2Defstr, materials); |
| } |
| return 0; |
| } |
| |
| string GroupName(string grp) { |
| if (initialized) { |
| if (member(material_groups, getMatGroupId(grp))) |
| return material_groups[getMatGroupId(grp)][P_NAME]; |
| else |
| return "Unbekanntes"; |
| } |
| } |
| |
| string GroupDescription(string grp) { |
| if (initialized) { |
| if (member(material_groups, getMatGroupId(grp))) |
| return material_groups[getMatGroupId(grp)][P_DESCRIPTION]; |
| else |
| return "Gruppe unbekannt"; |
| } |
| } |
| |
| //==================== Generieren von Headerfile und Manpages |
| private string *get_ordered_groups() |
| { |
| return ({"MATGROUP_WOOD", "MATGROUP_JEWEL", "MATGROUP_STONE", "MATGROUP_MAGNETIC", |
| "MATGROUP_METAL", "MATGROUP_DRUG", "MATGROUP_HERBAL", "MATGROUP_FLEXIBLE", |
| "MATGROUP_BIO", "MATGROUP_ACIDIC", "MATGROUP_BASIC", "MATGROUP_POISONOUS", |
| "MATGROUP_EXPLOSIVE", "MATGROUP_INFLAMMABLE", |
| "MATGROUP_ELEMENTAL", "MATGROUP_ELECTRICAL", "MATGROUP_MAGIC", |
| "MATGROUP_HOLY", "MATGROUP_UNHOLY", "MATGROUP_INVIS", |
| "MATGROUP_SOLID", "MATGROUP_FLUID", "MATGROUP_GAS"}); |
| } |
| private string gen_material_h_head() |
| { |
| return |
| "// MorgenGrauen MUDlib\n//\n" |
| "// materials.h -- material definitions\n//\n" |
| "// This file is generated by /secure/materialdb.c\n//\n" |
| "// DO NOT EDIT!\n//\n" |
| "// $Id: materialdb.c 8755 2014-04-26 13:13:40Z Zesstra $\n\n" |
| "#ifndef __MATERIALS_H__\n" |
| "#define __MATERIALS_H__\n\n"; |
| } |
| private string gen_material_h_material(string mat, string last_grp) |
| { |
| mat = old_mat_keys[mat]; |
| return sprintf("#define %-24s\"%-20s // %s\n", mat, |
| (member(materials[mat], P_DEFSTR)?materials[mat][P_DEFSTR]:mat)+"\"", |
| materials[mat][P_DESCRIPTION]||materials[mat][P_NAME][WER]); |
| } |
| private string gen_material_h_materials_grp(string grp, string *left) |
| { |
| string txt, *mats; |
| txt = sprintf("\n// Gruppe: %s\n", GroupName(grp)); |
| mats = GetGroupMembers(grp) - (GetGroupMembers(grp) - left); |
| txt += sprintf("%@s", map(sort_array(mats, #'>), #'gen_material_h_material)); |
| left -= GetGroupMembers(grp); |
| return txt; |
| } |
| private string gen_material_h_materials() |
| { |
| string txt, last_grp; |
| string *grps, *mats; |
| txt = "// ****************************** Materialien ******************************\n"; |
| // Gruppenweise ordnen |
| grps = get_ordered_groups(); |
| mats = AllMaterials(); |
| txt += sprintf("%@s", map(grps, #'gen_material_h_materials_grp, |
| &mats)); |
| // Übriggebliene Materialien ausgeben |
| txt += "// sonstige Materialien:\n"; |
| txt += sprintf("%@s", map(mats, #'gen_material_h_material)); |
| return txt; |
| } |
| private string gen_material_h_group(string grp) |
| { |
| return sprintf("#define %-27s\"%-18s // %s\n", |
| grp, groupKey2Defstr(grp)+"\"", GroupName(grp)); |
| } |
| private string gen_material_h_groups() |
| { |
| string txt; |
| txt = "\n// **************************** Materialgruppen ****************************\n\n" |
| "#ifndef _IS_MATERIALDB_\n"; |
| txt += sprintf("%@s\n", map(sort_array(m_indices(material_groups), #'>), |
| #'gen_material_h_group)); |
| txt += "\n#endif // _IS_MATERIALDB_\n"; |
| return txt; |
| } |
| private string gen_material_h_foot() |
| { |
| return |
| "#endif // __THING_MATERIAL_H__\n"; |
| } |
| private int dump_material_h(string fn) |
| { |
| return (write_file(fn, gen_material_h_head()) && |
| write_file(fn, gen_material_h_materials()) && |
| write_file(fn, gen_material_h_groups()) && |
| write_file(fn, gen_material_h_foot())); |
| } |
| private string gen_material_list_material(string mat) |
| { |
| mat = old_mat_keys[mat]; |
| return sprintf(" %-28s%=-45s\n", mat, |
| materials[mat][P_DESCRIPTION]||materials[mat][P_NAME][WER]); |
| } |
| private string gen_material_list_materials_grp(string grp, string *left) |
| { |
| string txt, *mats; |
| txt = sprintf("%s:\n", capitalize(GroupName(grp))); |
| mats = sort_array(GetGroupMembers(grp) - (GetGroupMembers(grp) - left), #'>); |
| txt += sprintf("%@s\n", map(mats, #'gen_material_list_material)); |
| left -= GetGroupMembers(grp); |
| return txt; |
| } |
| private void dump_material(string fn) |
| { |
| string txt; |
| string *grps, *mats; |
| // Gruppenweise ordnen |
| grps = get_ordered_groups(); |
| mats = AllMaterials(); |
| txt = sprintf("%@s", map(grps, #'gen_material_list_materials_grp, |
| &mats)); |
| // Übriggebliene Materialien ausgeben |
| txt += "sonstige Materialien:\n"; |
| txt += sprintf("%@s", map(mats, #'gen_material_list_material)); |
| write_file(fn, txt) || |
| raise_error(sprintf("Konnte Liste nicht weiter in Datei %s schreiben," |
| " Abbruch\n", fn)); |
| } |
| private void dump_group(string grp, string fn) |
| { |
| // upperstring langsame simul_efun, warum? |
| write_file(fn, sprintf(" %-28s%=-48s\n", (grp), |
| GroupName(grp))) || |
| raise_error(sprintf("Konnte Liste nicht weiter in Datei %s schreiben," |
| " Abbruch\n", fn)); |
| } |
| private string gen_doc_foot(string other) |
| { |
| return sprintf("\nSIEHE AUCH:\n" |
| " Konzepte: material, materialerkennung\n" |
| " Grundlegend: P_MATERIAL, /sys/materials.h, /sys/thing/material.h\n" |
| " Methoden: QueryMaterial(), QueryMaterialGroup(), MaterialList(),\n" |
| " Listen: AllMaterials(), AllGroups()\n" |
| " %s\n" |
| " Master: ConvMaterialList(), MaterialGroup(),\n" |
| " GroupName(), MaterialName(),\n" |
| " GetGroupMembers(), GetMatMembership()\n" |
| " Sonstiges: P_MATERIAL_KNOWLEDGE\n\n" |
| "%s generiert aus /secure/materialdb\n", other, dtime(time())); |
| } |
| |
| /* GenMatList |
| * |
| * Generiert Datei mit registrierten Materialien fuer die Dokumentation, |
| */ |
| varargs void GenMatList(string fn) |
| { |
| if (initialized) { |
| string txt; |
| if (!stringp(fn) || !sizeof(fn)) |
| fn = DOC_DIR("materialliste"); |
| if (file_size(fn) >= 0) { |
| printf("Datei %s existiert bereits, loesche sie\n", fn); |
| rm(fn); |
| } |
| if (write_file(fn, "Material Liste\n==============\n\n")) { |
| dump_material(fn); |
| write_file(fn, gen_doc_foot("materialgruppen")); |
| printf("Materialliste erfolgreich in Datei %s geschrieben\n", fn); |
| } else |
| printf("Konnte Liste nicht in Datei %s schreiben, Abbruch\n", fn); |
| } |
| } |
| |
| /* GenMatGroupList |
| * |
| * Generiert Datei mit registrierten Materialgruppen fuer die Dokumentation, |
| */ |
| varargs void GenMatGroupList(string fn) |
| { |
| if (initialized) { |
| string txt; |
| if (!stringp(fn) || !sizeof(fn)) |
| fn = DOC_DIR("materialgruppen"); |
| if (file_size(fn) >= 0) { |
| printf("Datei %s existiert bereits, loesche sie\n", fn); |
| rm(fn); |
| } |
| if (write_file(fn, "Materialgruppen\n===============\n")) { |
| map(sort_array(m_indices(material_groups), #'>), #'dump_group, fn); |
| write_file(fn, gen_doc_foot("materialliste")); |
| printf("Materialliste erfolgreich in Datei %s geschrieben\n", fn); |
| } else |
| printf("Konnte Liste nicht in Datei %s schreiben, Abbruch\n", fn); |
| } |
| } |
| |
| /* GenHeaderFile |
| * |
| * Generiert Headerfile mit Definitionen der moeglichen Materialien und |
| * Gruppen |
| */ |
| varargs void GenHeaderFile(string fn) |
| { |
| if (initialized) { |
| string txt; |
| if (!stringp(fn) || !sizeof(fn)) |
| fn = HEADERFILE; |
| if (file_size(fn) >= 0) { |
| printf("Datei %s existiert bereits, loesche sie\n", fn); |
| rm(fn); |
| } |
| if (dump_material_h(fn)) |
| printf("Headerdatei erfolgreich in %s geschrieben\n", fn); |
| else |
| printf("Konnte Headerdatei nicht in Datei %s schreiben, Abbruch\n", fn); |
| } |
| } |
| |
| //==================== Pruef- und Hilfsfunktionen fuer Materialien |
| private void updateGroupMembers(mapping groups, string mat_id, mapping mat) { |
| mixed *addgrps; // Array zum Ableiten von Gruppenzugehoerigkeiten |
| string *h; |
| int i, val; |
| mapping fractions; // Mapping mit Anteilen an Gruppen |
| fractions = mat[P_MG_FRACTIONS]; |
| if (!mappingp(fractions)) |
| fractions = ([]); |
| addgrps=({ // Reihenfolge wird rueckwaerts abgearbeitet |
| // Ableitungen sind z.T. abenteuerlich gewesen, mal ordentlich |
| // ausmisten. Die Zugehoerigkeit gehoert explizit in die |
| // Materialdefinition |
| // Gase sieht man normalerweise nicht: |
| ({"MATGROUP_INVIS", "MATGROUP_GAS"}), |
| // Mineralien sind auch Steine |
| ({"MATGROUP_STONE","MATGROUP_MINERAL"}), |
| // Edelmetalle sind Metalle: |
| ({"MATGROUP_METAL","MATGROUP_PRECIOUS_METAL"}), |
| // Lebewesen und deren Ueberreste, Paiere und Stoffe sind biologisch |
| ({"MATGROUP_BIO","MATGROUP_LIVING","MATGROUP_DEAD", |
| "MATGROUP_PAPER"}), |
| // Holz ist pflanzlich: |
| ({"MATGROUP_HERBAL", "MATGROUP_WOOD"}), |
| // Holz ist meistens tot: |
| ({"MATGROUP_DEAD","MATGROUP_WOOD"}), |
| // Holz, Papier und Stoffe brennen: |
| ({"MATGROUP_INFLAMMABLE","MATGROUP_WOOD","MATGROUP_PAPER"}), |
| // Laubhoelzer, Nadelhoelzer und Tropenhoelzer sind Holz |
| ({"MATGROUP_WOOD","MATGROUP_TROPICAL_WOOD","MATGROUP_DECIDUOUS_WOOD", |
| "MATGROUP_CONIFER_WOOD"}), |
| // Explosive Dinge sind immer entzuendlich: |
| ({"MATGROUP_INFLAMMABLE","MATGROUP_EXPLOSIVE"}) |
| }); |
| i=sizeof(addgrps); |
| while(i--) { |
| int j; |
| h=addgrps[i]; |
| if (member(fractions,h[0])) // Existiert schon eigener Eintrag? |
| continue; // Automatische Eintragung unnoetig |
| val=0; |
| for (j=sizeof(h)-1;j>=1;j--) |
| val+=fractions[h[j]]; |
| if (!val) |
| continue; |
| if (val>100) |
| val=100; |
| else if (val<-100) |
| val=-100; |
| fractions[h[0]]=val; |
| } |
| if (fractions["MATGROUP_LIVING"]) // Im Falle von lebendem Holz, tot loeschen |
| m_delete(fractions,"MATGROUP_DEAD"); |
| // Alles, was nicht als gasfoerming, fluessig oder fest eingeordnet ist, ist |
| // sonstwas: |
| if (!member(fractions, "MATGROUP_FLUID") |
| && !member(fractions, "MATGROUP_GAS") |
| && !member(fractions, "MATGROUP_SOLID")) |
| fractions["MATGROUP_MISC"]=100; |
| // Materialien als Mitglieder in die Gruppen eintragen |
| addgrps=m_indices(fractions); |
| i=sizeof(addgrps); |
| while(i--) { |
| mixed ind; |
| ind=addgrps[i]; |
| if (!fractions[ind] || !member(groups, ind)) { |
| // Unbekannte Gruppe und Gruppe ohne Anteil aus Mapping loeschen |
| m_delete(fractions,ind); |
| continue; |
| } |
| if (!pointerp(h=groups[ind][P_MEMBERS])) |
| h=({}); |
| h+=({mat_id}); |
| groups[ind][P_MEMBERS]=h; |
| } |
| mat[P_MG_FRACTIONS] = fractions; |
| } |
| |
| //==================== Einlesen der Mappings aus Dateien |
| |
| #define MDESC_ERROR(x, y) LOG_ERROR(sprintf("Materialbeschreibung '%s': %s\n", x, y)) |
| #define MDESC_WARN(x, y) //LOG_WARN(sprintf("Materialbeschreibung '%s': %s\n", x, y)) |
| |
| private mapping getDescParts(string s) { |
| string* lines; |
| string key, val; |
| int i, n; |
| mapping m; |
| m = ([]); |
| val = ""; |
| lines = explode(s, "\n"); |
| n = sizeof(lines); |
| if (n > 0) { |
| while (i < n) { |
| if (sscanf(lines[i], "%s:", key)) { |
| status multiline; |
| multiline = 0; |
| // Schluessel gefunden, Wert auslesen |
| while ( (++i < n) && sizeof(lines[i])) { |
| // Mehrzeilige Werte mit newline verketten |
| if (multiline) { |
| val += "\n"; |
| } |
| val += lines[i]; |
| multiline = 1; |
| } |
| m += ([key:val]); |
| val = ""; |
| } |
| i++; |
| } |
| } |
| return m; |
| } |
| private varargs int isFile(string fn, string path) { |
| if (stringp(path) && sizeof(path)) |
| fn = path+"/"+fn; |
| return (file_size(fn) >= 0); |
| } |
| |
| private varargs mixed readGroupDesc(string id) { |
| mixed m; |
| string fn; |
| fn = MAT_DIR+"/groups/"+id; |
| if (file_size(fn) > 0) { |
| mapping parts; |
| string desc; |
| parts = getDescParts(read_file(fn)); |
| m = ([P_NAME:parts["Name"], |
| P_MEMBERS:({})]); |
| if (member(parts,"Beschreibung")) |
| m += ([P_DESCRIPTION:parts["Beschreibung"]]); |
| if (parts["Gruppenid"] != id) |
| LOG_WARN(sprintf("Unstimmigkeit Gruppenid bei '%s'\n", id)); |
| } else { |
| LOG_ERROR(sprintf("Kann Gruppenbeschreibung %s nicht laden\n", fn)); |
| } |
| return m; |
| } |
| |
| private mapping convMatId(string s) { |
| mapping m; |
| string* parts; |
| parts = explode(s, "\""); |
| if (sizeof(parts)) { |
| int ende; |
| ende = strstr(parts[0]," ")-1; |
| if (ende < 0) |
| ende = sizeof(parts[0]); |
| m = ([P_ID:parts[0][0..ende]]); |
| if (sizeof(parts) > 1) |
| m += ([P_DEFSTR:parts[1]]); |
| } |
| return m; |
| } |
| private string* convMatNames(string s) { |
| string* names; |
| names = filter(explode(s, "\""), |
| lambda( ({'x}), ({#'>, ({#'sizeof, 'x}), 1}) )); |
| if (sizeof(names)<1) |
| names=0; |
| else { |
| if (sizeof(names)<2) |
| names+=({names[0]+"s"}); |
| if (sizeof(names)<3) |
| names+=({names[0]}); |
| if (sizeof(names)<4) |
| names+=({names[0]}); |
| } |
| return names; |
| } |
| private int convMatGender(string s) { |
| int gender; |
| s = lowerstring(s); |
| // Ein Buchstabe reicht zur Bestimmung. Wenn nur weiblich|female |
| // bzw. maennlich|male verwendet wird. Dabei ist dann allerdings die |
| // Reihenfolge der Auswertung wichtig, damit das m bei MALE nicht mehr bei |
| // female passt. |
| if (sizeof(regexp( ({s}), "f|w"))) { |
| gender = FEMALE; |
| } else if (sizeof(regexp( ({s}), "m"))) { |
| gender = MALE; |
| } else { |
| gender = NEUTER; |
| } |
| return gender; |
| } |
| private string convMatDesc(string s) { |
| if (sizeof(regexp( ({s}), "- nicht vorhanden -"))) { |
| s = 0; |
| } else { |
| // Mehrzeilige Beschreibungen zu einer Zeile zusammenfassen |
| s = implode(explode(s, "\n"), " "); |
| } |
| return s; |
| } |
| private void addRecocLine(string s, mixed* r) { |
| // Die weitere Bewertung der Schwierigkeit kann erst vorgenommen werden, |
| // wenn alle Materialien bekannt sind und passiert spaeter. Zuerst werden |
| // nur die Elemente des Arrays konvertiert und eingetragen |
| string mat; |
| int val; |
| if (sscanf(s, "%s:%d", mat, val)) { |
| r += ({mat,val}); |
| } else if (sscanf(s, "%d", val)) { |
| r += ({val}); |
| } else { |
| r += ({s}); |
| } |
| } |
| private mixed convMatRec(string s) { |
| mixed difficulties; |
| if (sizeof(regexp( ({s}), "- keine Einschraenkung -"))) { |
| difficulties = 0; |
| } else { |
| difficulties = ({}); |
| // Jede Zeile enthaelt eine Bedingung |
| map(explode(s, "\n"), #'addRecocLine, &difficulties); |
| } |
| return difficulties; |
| } |
| private void addGroupLine(string s, mapping g) { |
| // Die weitere Bewertung der Zugehoerigkeit passiert spaeter. |
| string grp; |
| int val; |
| if (sscanf(s, "%s:%d", grp, val)) { |
| g += ([grp:val]); |
| } else { |
| g += ([grp:100]); |
| } |
| } |
| private mapping convMatGroups(string s) { |
| mapping groups; |
| if (!sizeof(regexp( ({s}), "- keine -"))) { |
| groups = ([]); |
| // Jede Zeile enthaelt eine Bedingung |
| map(explode(s, "\n"), #'addGroupLine, groups); |
| } |
| return groups; |
| } |
| private mapping convMaterialDesc(string id, mapping desc) { |
| /* Struktur Materialmapping: |
| P_GENDER, |
| P_NAME:({name_nom, name_gen, name_dativ, name_akkusativ}), |
| (P_RECOC:({mat1,faehigkeit1,mat2,faehigkeit2,...}),) |
| (P_DEFSTR: bei bedarf), |
| P_DESCRIPTION, |
| (grupp1:anteil1, |
| gruppe2:anteil2, |
| ...) |
| */ |
| mapping m; |
| mixed val, val2; |
| m = ([]); |
| // Der string fuer das #define zuerst: |
| val = convMatId(desc["Materialid"]); |
| if (mappingp(val)) { |
| if (val[P_ID] != id) |
| LOG_WARN(sprintf("Unstimmigkeit Materialid bei '%s':%O\n", id, val[P_ID])); |
| if (member(val, P_DEFSTR)) { |
| m += ([P_DEFSTR:val[P_DEFSTR]]); |
| } else { |
| // Wenn kein String fuers #define angegeben wurde, dann direkt ID verwenden |
| //m += ([P_DEFSTR:lowerstring(id)[4..]]); |
| } |
| } |
| // Die Namen |
| if (val = convMatNames(desc["Name"])) { |
| m += ([P_NAME:val]); |
| } else { |
| MDESC_WARN(id, "keine Namen"); |
| m += ([P_NAME:({"", "", "", ""})]); |
| } |
| // Das Geschlecht, standard ist NEUTER |
| m += ([P_GENDER:convMatGender(desc["Geschlecht"]) ]); |
| // Die Beschreibung |
| val = convMatDesc(desc["Beschreibung"]); |
| if (sizeof(val)) { |
| m += ([P_DESCRIPTION:val]); |
| } else { |
| MDESC_WARN(id, "keine Beschreibung"); |
| } |
| // Die Erkennbarkeit |
| val = convMatRec(desc["Erkennbarkeit"]); |
| if (sizeof(val)) { |
| m += ([P_RECOC:val]); |
| } |
| // und zum Schluss die Gruppenzugehoerigkeit |
| val = convMatGroups(desc["Gruppenzugehoerigkeit"]); |
| if (mappingp(val) && sizeof(val)) { |
| m += ([P_MG_FRACTIONS:val]); |
| } |
| return m; |
| } |
| private varargs mixed readMaterialDesc(string id) { |
| mixed m; |
| string fn; |
| fn = MAT_DIR+"/materials/"+id; |
| if (file_size(fn) > 0) { |
| mapping parts; |
| string desc; |
| parts = getDescParts(read_file(fn)); |
| m = convMaterialDesc(id, parts); |
| } else { |
| LOG_ERROR(sprintf("MDB:Kann Materialbeschreibung %s nicht laden\n", fn)); |
| } |
| return m; |
| } |
| |
| public int GetUpdateTicks() { |
| return updateTicks; |
| } |
| |
| private void scanFinished() { |
| isScanning = 0; |
| initialized = 1; |
| // Mappings umkopieren |
| materials = new_materials; |
| material_groups = new_material_groups; |
| // Letzter Schritt: Mapping mit alten Schluesseln anlegen |
| old_mat_keys = mkmapping(map(m_indices(materials), #'matKey2Defstr, materials), |
| m_indices(materials)); |
| // Generieren der Doku und des Materialheaders |
| GenHeaderFile(); |
| GenMatList(); |
| GenMatGroupList(); |
| // Savefile schreiben |
| save_object(SAVEFILE); |
| } |
| |
| public int IsScanning() { |
| return isScanning; |
| } |
| |
| private varargs void doScanMaterials(string* mats, int i, int step) { |
| int ticks, start; |
| string matid; |
| start = get_eval_cost(); |
| if (step < 2) { |
| while ( (i < sizeof(mats)) && |
| ((start - get_eval_cost()) < query_limits()[LIMIT_EVAL]/3 ) ) { |
| matid = mats[i]; |
| switch (step) { |
| case 0: |
| // Erster Schritt: Einlesen der Dateien |
| new_materials[matid] = readMaterialDesc(matid); |
| break; |
| case 1: |
| // Zweiter Schritt: Bearbeiten der Erkennung und Gruppenzugehoerigkeit |
| updateGroupMembers(new_material_groups, matid, new_materials[matid]); |
| break; |
| default: |
| break; |
| } |
| i++; |
| } |
| } |
| if (i < sizeof(mats)) { |
| catch(raise_error(sprintf("MaterialDB: Initialisierung noch nicht beendet," |
| " fehlende Materialbeschreibungen moeglich" |
| " (Phase %d:%d/%d)\n", |
| step, i, sizeof(mats)));publish); |
| call_out(#'doScanMaterials, 2, mats, i, step); |
| } else { |
| // Zweite Stufe ausloesen oder beenden |
| if (step < 1) { |
| if ((start - get_eval_cost()) < query_limits()[LIMIT_EVAL]/2 ) |
| doScanMaterials(mats, 0, step+1); |
| else |
| call_out(#'doScanMaterials, 2, mats, 0, step+1); |
| } |
| else |
| scanFinished(); |
| } |
| updateTicks += start - get_eval_cost(); |
| } |
| |
| private mapping ScanGroups() { |
| mapping groups; |
| string* grpfiles; |
| groups = ([]); |
| grpfiles = filter(get_dir(MAT_DIR+"/groups/MATGROUP_*"), |
| #'isFile, MAT_DIR+"/groups"); |
| groups = mkmapping(grpfiles, map(grpfiles, #'readGroupDesc, 1)); |
| return groups; |
| } |
| |
| private void ScanMaterials() { |
| string *matfiles; |
| matfiles = filter(get_dir(MAT_DIR+"/materials/MAT_*"), |
| #'isFile, MAT_DIR+"/materials"); |
| doScanMaterials(matfiles); |
| } |
| |
| void Update() { |
| int start; |
| updateTicks = 0; |
| start = get_eval_cost(); |
| if (!isScanning) { |
| if (sizeof(get_dir(MAT_DIR))) { |
| isScanning = 1; |
| new_material_groups = ScanGroups(); |
| new_materials = ([]); |
| updateTicks = start - get_eval_cost(); |
| ScanMaterials(); |
| } else { |
| LOG_ERROR("Kann Materialverzeichnis nicht finden, keine Materialien angelegt!\n"); |
| } |
| } |
| } |