MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | // MorgenGrauen MUDlib |
| 2 | // |
| 3 | // - Prototypen und Properties in thing/material.h |
| 4 | // - Liste in materials.h |
| 5 | // |
| 6 | // TODO: properties.h um materials.h erweitern |
| 7 | // |
| 8 | // - implizite Gruppenzuordnung entfernen, da jetzt explizit in |
| 9 | // Definitionsdateien vorhanden |
| 10 | // - Materialdoku ueberarbeiten, dabei Hinweis auf nicht mehr implizite |
| 11 | // Gruppenzuordnung |
| 12 | // /p/daemon/materialdb.c -- Materialdatenbank |
| 13 | // |
| 14 | // $Id: materialdb.c 8755 2014-04-26 13:13:40Z Zesstra $ |
| 15 | |
| 16 | #pragma strong_types |
| 17 | #pragma no_clone |
| 18 | #pragma no_inherit |
| 19 | #pragma no_shadow |
| 20 | #pragma pedantic |
| 21 | |
| 22 | // Die Propertydefinition reinholen |
| 23 | #include <language.h> |
| 24 | #include <thing/description.h> |
| 25 | // Materialliste nicht mit reinziehen |
| 26 | #define _SKIP_MATERIALS_ |
| 27 | #include <thing/material.h> |
| 28 | #include <player/description.h> |
| 29 | #include <rtlimits.h> |
| 30 | |
| 31 | // Basisverzeichnis der Materialien |
| 32 | #define MAT_DIR "/doc/materials" |
| 33 | |
| 34 | // Ausgabeverzeichnis fuer Doku |
| 35 | #define DOC_DIR(x) ("/doc/materials/"+x) |
| 36 | |
| 37 | // Dateiname des Headers mit Materialdefinitionen |
| 38 | #define HEADERFILE "/sys/materials.h" |
| 39 | |
| 40 | // Savefile. |
| 41 | #define SAVEFILE DOC_DIR("materialdb") |
| 42 | |
| 43 | // Rein intern verwendete Namen |
| 44 | #define P_RECOC "recognizability" |
| 45 | #define P_ID "id" |
| 46 | #define P_DEFSTR "defstr" |
| 47 | #define P_MEMBERS "members" |
| 48 | #define P_MG_FRACTIONS "mg_fractions" |
| 49 | |
| 50 | #define LOG_ERROR(x) if(find_player("raschaua")&&find_player("raschaua")->QueryProp("mdb-debug"))tell_object(find_player("raschaua"),"MDB-Error:"+x) |
| 51 | #define LOG_WARN(x) if(find_player("raschaua")&&find_player("raschaua")->QueryProp("mdb-debug"))tell_object(find_player("raschaua"),"MDB-Warn:"+x) |
| 52 | |
| 53 | // Prototypes: |
| 54 | // (Liefert den Anteil der Materialgruppe grp an mats) |
| 55 | int MaterialGroup(mapping mats, string grp); |
| 56 | // Konvertiert eine Liste von Materialien zu ihren Namen, dabei wird die |
| 57 | // Erkennungsfaehigkeit beruecksichtigt und evtl. falsch erkannt |
| 58 | varargs string ConvMaterialList(mixed mats, int casus, mixed idinf); |
| 59 | varargs string MaterialName(string mat, int casus, mixed idinf); |
| 60 | // Gibt den Namen einer Materialgruppe zurueck |
| 61 | string GroupName(string grp); |
| 62 | // Gibt alle Materialien zurueck |
| 63 | string *AllMaterials(); |
| 64 | // Gibt alle Gruppen zurueck |
| 65 | string *AllGroups(); |
| 66 | // Gibt alle Gruppen zurueck, in denen mat enthalten ist |
| 67 | string *GetMatMembership(string mat); |
| 68 | // Gibt alle Materialien zurueck, die in grp enthalten sind |
| 69 | string *GetGroupMembers(string grp); |
| 70 | // Erneuert die Materialien durch Scannen des Materialverzeichnisses |
| 71 | void Update(); |
| 72 | // generiert Headerfile aus den Daten |
| 73 | varargs void GenHeaderFile(string fn); |
| 74 | |
| 75 | mapping materials; |
| 76 | mapping material_groups; |
| 77 | private status initialized; |
| 78 | mapping old_mat_keys; // Alter Materialkey -> neuer Key (Kompatibilitaet) |
| 79 | nosave mapping new_materials; // Materialien waehrend des Scannens |
| 80 | nosave mapping new_material_groups; // Materialgruppen waehrend des Scannens |
| 81 | private nosave status isScanning; |
| 82 | private nosave int updateTicks; |
| 83 | |
| 84 | void create() { |
| 85 | seteuid(getuid()); |
| 86 | // Savefile einlesen, falls moeglich, damit die DB direkt initialisert ist, |
| 87 | // wenn auch ggf. mit alten Daten. |
| 88 | restore_object(SAVEFILE); |
| 89 | if (initialized) { |
| 90 | // falls erfolgreich, direkt Header fuer die Mudlib schreiben |
| 91 | GenHeaderFile(); |
| 92 | } |
| 93 | // jetzt Update der Daten durchfuehren. |
| 94 | Update(); |
| 95 | } |
| 96 | |
| 97 | //==================== Umwandeln der Strings aus der thing/material.h |
| 98 | private string getMatId(string key) { |
| 99 | // Alte Bezeichner umwandeln |
| 100 | if (!member(materials, key)) |
| 101 | key = old_mat_keys[key]; |
| 102 | return key; |
| 103 | } |
| 104 | private string getMatGroupId(string key) { |
| 105 | // Alte Bezeichner umwandeln |
| 106 | if (!member(material_groups, key)) |
| 107 | key = "MATGROUP_"+upperstring(key[3..]); |
| 108 | return key; |
| 109 | } |
| 110 | private string matKey2Defstr(string key, mapping mats) { |
| 111 | string id; |
| 112 | if (member(mats[key], P_DEFSTR)) |
| 113 | id = mats[key][P_DEFSTR]; |
| 114 | else |
| 115 | id = key; |
| 116 | return id; |
| 117 | } |
| 118 | private string groupKey2Defstr(string key) { |
| 119 | if (sizeof(key) > 9) |
| 120 | key = "mg_"+lowerstring(key[9..]); |
| 121 | else |
| 122 | key = ""; |
| 123 | return key; |
| 124 | } |
| 125 | |
| 126 | //==================== Schnittstellenfunktionen zur Verwendung der DB |
| 127 | varargs string MaterialName(string mat, int casus, mixed idinf) { |
| 128 | if (initialized) { |
| 129 | string *names; |
| 130 | mapping props; |
| 131 | mixed *dif; |
| 132 | // Anpassen der Materialid |
| 133 | mat = getMatId(mat); |
| 134 | |
| 135 | if (!mappingp(props=materials[mat])) |
| 136 | props=([]); |
| 137 | |
| 138 | // Je nach Koennen des Spielers kann man das exakte Material |
| 139 | // mehr oder weniger gut erkennen: |
| 140 | if (pointerp(dif=props[P_RECOC]) |
| 141 | && (!intp(idinf)||idinf<100) ) { // 100=exakte Erkennung |
| 142 | int i, n, recval; |
| 143 | mixed *grps, tmp, x; |
| 144 | |
| 145 | recval=0; |
| 146 | grps=props[P_MG_FRACTIONS]; |
| 147 | if (!pointerp(idinf)) |
| 148 | idinf=({idinf}); |
| 149 | |
| 150 | // Zunaechst die Faehigkeit des Spielers (da koennen noch |
| 151 | // Gildenfaehigkeiten hinzu kommen) ermitteln, dieses |
| 152 | // Material zu erkennen: |
| 153 | i=sizeof(idinf); |
| 154 | while(i--) { |
| 155 | tmp=idinf[i]; |
| 156 | if (objectp(tmp)) // Diese Property ist hauptsaechlich fuer Rassen: |
| 157 | tmp=tmp->QueryProp(P_MATERIAL_KNOWLEDGE); |
| 158 | if (intp(tmp)) { |
| 159 | recval+=tmp; // Allgemeine Erkennungsfaehigkeit |
| 160 | break; |
| 161 | } |
| 162 | if (closurep(tmp) && intp(x=funcall(tmp,mat,grps))) { |
| 163 | recval+=x; |
| 164 | break; // Closures koennen immer nuetzlich sein :) |
| 165 | } |
| 166 | if (mappingp(tmp)) { |
| 167 | int j; |
| 168 | if ((x=tmp[mat]) && intp(x)){ |
| 169 | // Erkennung von speziell diesem Material |
| 170 | recval+=x; |
| 171 | break; |
| 172 | } |
| 173 | // Erkennung von Gruppen |
| 174 | j=sizeof(grps); |
| 175 | while(j--) |
| 176 | if((x=tmp[grps[j]]) && intp(x)) |
| 177 | recval+=x; |
| 178 | if (pointerp(tmp=tmp[MATERIAL_SYMMETRIC_RECOGNIZABILITY])) { |
| 179 | for (j=sizeof(tmp)-2;j>=0;j-=2) { |
| 180 | if (!intp(x=tmp[j+1])) |
| 181 | raise_error("materialdb: illegal sym.recoc. format\n"); |
| 182 | if (props[tmp[j]]) |
| 183 | recval+=x; |
| 184 | else // bei passenden Gruppen +, bei anderen - |
| 185 | recval-=x; |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | // Jetzt wird ermittelt, ob vielleicht eine ungenauere |
| 192 | // Beschreibung gegeben werden soll: |
| 193 | x=dif[0]; |
| 194 | n = sizeof(dif)-1; |
| 195 | for (i=2;i<=n;i+=2) { |
| 196 | if (recval>=dif[i-1]) |
| 197 | x=dif[i]; |
| 198 | } |
| 199 | // Wenn die Faehigkeiten des Spielers nicht fuer den echten Klarnamen |
| 200 | // ausreichen, gib die Alternative zurueck: |
| 201 | if (x!=mat) |
| 202 | return MaterialName(x, casus, 100); |
| 203 | } |
| 204 | |
| 205 | if (!pointerp(names=props[P_NAME]) || sizeof(names)<4) |
| 206 | names=({"unbekanntes Material", "unbekannten Materials", |
| 207 | "unbekanntem Material", "unbekannten Material"}); |
| 208 | if (casus<0 || casus>3) |
| 209 | casus=0; |
| 210 | return names[casus]; |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | varargs string ConvMaterialList(mixed mats, int casus, mixed idinf) { |
| 215 | if (initialized) { |
| 216 | string *ms,ml; |
| 217 | int i; |
| 218 | |
| 219 | ml=""; |
| 220 | if (mappingp(mats)) |
| 221 | ms=m_indices(mats); |
| 222 | else if (stringp(mats)) |
| 223 | ms=({mats}); |
| 224 | else if (pointerp(mats)) |
| 225 | ms=mats; |
| 226 | else |
| 227 | ms=({}); |
| 228 | i=sizeof(ms); |
| 229 | while(i) { |
| 230 | ml+=MaterialName(ms[--i],casus,idinf); |
| 231 | if (i) |
| 232 | ml+=((i>1)?", ":" und "); |
| 233 | } |
| 234 | return ml; |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | int MaterialGroup(mapping mats, string grp) { |
| 239 | if (initialized) { |
| 240 | string *ms; |
| 241 | int i,res; |
| 242 | |
| 243 | res=0; |
| 244 | if (!mappingp(mats) || !stringp(grp)) |
| 245 | return res; |
| 246 | ms=m_indices(mats); |
| 247 | i=sizeof(ms); |
| 248 | while(i--) { |
| 249 | string mat; |
| 250 | mapping props; |
| 251 | mat=ms[i]; |
| 252 | if (mappingp(props=materials[getMatId(mat)])) |
| 253 | res+=(mats[mat]*props[P_MG_FRACTIONS][getMatGroupId(grp)])/100; |
| 254 | } |
| 255 | if (res<-100) // Vielleicht noch Antimaterie zulassen |
| 256 | res=-100; // (noch nicht sicher ob das so bleiben wird oder 0 sein wird) |
| 257 | if (res>100) |
| 258 | res=100; |
| 259 | return res; |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | string *AllMaterials() { |
| 264 | if (initialized) { |
| 265 | // Aus Kompatibilitaetsgruenden die alten Schluessel (#define-String) |
| 266 | // zurueckgeben |
| 267 | return m_indices(old_mat_keys); |
| 268 | } |
| 269 | return 0; |
| 270 | } |
| 271 | |
| 272 | string *AllGroups() { |
| 273 | if (initialized) { |
| 274 | // Aus Kompatibilitaetsgruenden die alten Schluessel (#define-String) |
| 275 | // zurueckgeben |
| 276 | return map(m_indices(material_groups), #'groupKey2Defstr); |
| 277 | } |
| 278 | return 0; |
| 279 | } |
| 280 | |
| 281 | string *GetMatMembership(string mat) { |
| 282 | if (initialized) { |
| 283 | mapping props; |
| 284 | // Anpassen der Materialid |
| 285 | mat = getMatId(mat); |
| 286 | |
| 287 | if (!mappingp(props=materials[mat])) |
| 288 | return ({}); |
| 289 | return map(m_indices(props[P_MG_FRACTIONS]), #'groupKey2Defstr); |
| 290 | } |
| 291 | return 0; |
| 292 | } |
| 293 | |
| 294 | string *GetGroupMembers(string grp) { |
| 295 | if (initialized) { |
| 296 | string *mats; |
| 297 | // Anpassen der Materialid |
| 298 | grp = getMatGroupId(grp); |
| 299 | if (!member(material_groups, grp) || |
| 300 | !pointerp(mats=material_groups[grp][P_MEMBERS])) |
| 301 | return ({}); |
| 302 | return map(mats, #'matKey2Defstr, materials); |
| 303 | } |
| 304 | return 0; |
| 305 | } |
| 306 | |
| 307 | string GroupName(string grp) { |
| 308 | if (initialized) { |
| 309 | if (member(material_groups, getMatGroupId(grp))) |
| 310 | return material_groups[getMatGroupId(grp)][P_NAME]; |
| 311 | else |
| 312 | return "Unbekanntes"; |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | string GroupDescription(string grp) { |
| 317 | if (initialized) { |
| 318 | if (member(material_groups, getMatGroupId(grp))) |
| 319 | return material_groups[getMatGroupId(grp)][P_DESCRIPTION]; |
| 320 | else |
| 321 | return "Gruppe unbekannt"; |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | //==================== Generieren von Headerfile und Manpages |
| 326 | private string *get_ordered_groups() |
| 327 | { |
| 328 | return ({"MATGROUP_WOOD", "MATGROUP_JEWEL", "MATGROUP_STONE", "MATGROUP_MAGNETIC", |
| 329 | "MATGROUP_METAL", "MATGROUP_DRUG", "MATGROUP_HERBAL", "MATGROUP_FLEXIBLE", |
| 330 | "MATGROUP_BIO", "MATGROUP_ACIDIC", "MATGROUP_BASIC", "MATGROUP_POISONOUS", |
| 331 | "MATGROUP_EXPLOSIVE", "MATGROUP_INFLAMMABLE", |
| 332 | "MATGROUP_ELEMENTAL", "MATGROUP_ELECTRICAL", "MATGROUP_MAGIC", |
| 333 | "MATGROUP_HOLY", "MATGROUP_UNHOLY", "MATGROUP_INVIS", |
| 334 | "MATGROUP_SOLID", "MATGROUP_FLUID", "MATGROUP_GAS"}); |
| 335 | } |
| 336 | private string gen_material_h_head() |
| 337 | { |
| 338 | return |
| 339 | "// MorgenGrauen MUDlib\n//\n" |
| 340 | "// materials.h -- material definitions\n//\n" |
| 341 | "// This file is generated by /secure/materialdb.c\n//\n" |
| 342 | "// DO NOT EDIT!\n//\n" |
| 343 | "// $Id: materialdb.c 8755 2014-04-26 13:13:40Z Zesstra $\n\n" |
| 344 | "#ifndef __MATERIALS_H__\n" |
| 345 | "#define __MATERIALS_H__\n\n"; |
| 346 | } |
| 347 | private string gen_material_h_material(string mat, string last_grp) |
| 348 | { |
| 349 | mat = old_mat_keys[mat]; |
| 350 | return sprintf("#define %-24s\"%-20s // %s\n", mat, |
| 351 | (member(materials[mat], P_DEFSTR)?materials[mat][P_DEFSTR]:mat)+"\"", |
| 352 | materials[mat][P_DESCRIPTION]||materials[mat][P_NAME][WER]); |
| 353 | } |
| 354 | private string gen_material_h_materials_grp(string grp, string *left) |
| 355 | { |
| 356 | string txt, *mats; |
| 357 | txt = sprintf("\n// Gruppe: %s\n", GroupName(grp)); |
| 358 | mats = GetGroupMembers(grp) - (GetGroupMembers(grp) - left); |
| 359 | txt += sprintf("%@s", map(sort_array(mats, #'>), #'gen_material_h_material)); |
| 360 | left -= GetGroupMembers(grp); |
| 361 | return txt; |
| 362 | } |
| 363 | private string gen_material_h_materials() |
| 364 | { |
| 365 | string txt, last_grp; |
| 366 | string *grps, *mats; |
| 367 | txt = "// ****************************** Materialien ******************************\n"; |
| 368 | // Gruppenweise ordnen |
| 369 | grps = get_ordered_groups(); |
| 370 | mats = AllMaterials(); |
| 371 | txt += sprintf("%@s", map(grps, #'gen_material_h_materials_grp, |
| 372 | &mats)); |
| 373 | // Übriggebliene Materialien ausgeben |
| 374 | txt += "// sonstige Materialien:\n"; |
| 375 | txt += sprintf("%@s", map(mats, #'gen_material_h_material)); |
| 376 | return txt; |
| 377 | } |
| 378 | private string gen_material_h_group(string grp) |
| 379 | { |
| 380 | return sprintf("#define %-27s\"%-18s // %s\n", |
| 381 | grp, groupKey2Defstr(grp)+"\"", GroupName(grp)); |
| 382 | } |
| 383 | private string gen_material_h_groups() |
| 384 | { |
| 385 | string txt; |
| 386 | txt = "\n// **************************** Materialgruppen ****************************\n\n" |
| 387 | "#ifndef _IS_MATERIALDB_\n"; |
| 388 | txt += sprintf("%@s\n", map(sort_array(m_indices(material_groups), #'>), |
| 389 | #'gen_material_h_group)); |
| 390 | txt += "\n#endif // _IS_MATERIALDB_\n"; |
| 391 | return txt; |
| 392 | } |
| 393 | private string gen_material_h_foot() |
| 394 | { |
| 395 | return |
| 396 | "#endif // __THING_MATERIAL_H__\n"; |
| 397 | } |
| 398 | private int dump_material_h(string fn) |
| 399 | { |
| 400 | return (write_file(fn, gen_material_h_head()) && |
| 401 | write_file(fn, gen_material_h_materials()) && |
| 402 | write_file(fn, gen_material_h_groups()) && |
| 403 | write_file(fn, gen_material_h_foot())); |
| 404 | } |
| 405 | private string gen_material_list_material(string mat) |
| 406 | { |
| 407 | mat = old_mat_keys[mat]; |
| 408 | return sprintf(" %-28s%=-45s\n", mat, |
| 409 | materials[mat][P_DESCRIPTION]||materials[mat][P_NAME][WER]); |
| 410 | } |
| 411 | private string gen_material_list_materials_grp(string grp, string *left) |
| 412 | { |
| 413 | string txt, *mats; |
| 414 | txt = sprintf("%s:\n", capitalize(GroupName(grp))); |
| 415 | mats = sort_array(GetGroupMembers(grp) - (GetGroupMembers(grp) - left), #'>); |
| 416 | txt += sprintf("%@s\n", map(mats, #'gen_material_list_material)); |
| 417 | left -= GetGroupMembers(grp); |
| 418 | return txt; |
| 419 | } |
| 420 | private void dump_material(string fn) |
| 421 | { |
| 422 | string txt; |
| 423 | string *grps, *mats; |
| 424 | // Gruppenweise ordnen |
| 425 | grps = get_ordered_groups(); |
| 426 | mats = AllMaterials(); |
| 427 | txt = sprintf("%@s", map(grps, #'gen_material_list_materials_grp, |
| 428 | &mats)); |
| 429 | // Übriggebliene Materialien ausgeben |
| 430 | txt += "sonstige Materialien:\n"; |
| 431 | txt += sprintf("%@s", map(mats, #'gen_material_list_material)); |
| 432 | write_file(fn, txt) || |
| 433 | raise_error(sprintf("Konnte Liste nicht weiter in Datei %s schreiben," |
| 434 | " Abbruch\n", fn)); |
| 435 | } |
| 436 | private void dump_group(string grp, string fn) |
| 437 | { |
| 438 | // upperstring langsame simul_efun, warum? |
| 439 | write_file(fn, sprintf(" %-28s%=-48s\n", (grp), |
| 440 | GroupName(grp))) || |
| 441 | raise_error(sprintf("Konnte Liste nicht weiter in Datei %s schreiben," |
| 442 | " Abbruch\n", fn)); |
| 443 | } |
| 444 | private string gen_doc_foot(string other) |
| 445 | { |
| 446 | return sprintf("\nSIEHE AUCH:\n" |
| 447 | " Konzepte: material, materialerkennung\n" |
| 448 | " Grundlegend: P_MATERIAL, /sys/materials.h, /sys/thing/material.h\n" |
| 449 | " Methoden: QueryMaterial(), QueryMaterialGroup(), MaterialList(),\n" |
| 450 | " Listen: AllMaterials(), AllGroups()\n" |
| 451 | " %s\n" |
| 452 | " Master: ConvMaterialList(), MaterialGroup(),\n" |
| 453 | " GroupName(), MaterialName(),\n" |
| 454 | " GetGroupMembers(), GetMatMembership()\n" |
| 455 | " Sonstiges: P_MATERIAL_KNOWLEDGE\n\n" |
| 456 | "%s generiert aus /secure/materialdb\n", other, dtime(time())); |
| 457 | } |
| 458 | |
| 459 | /* GenMatList |
| 460 | * |
| 461 | * Generiert Datei mit registrierten Materialien fuer die Dokumentation, |
| 462 | */ |
| 463 | varargs void GenMatList(string fn) |
| 464 | { |
| 465 | if (initialized) { |
| 466 | string txt; |
| 467 | if (!stringp(fn) || !sizeof(fn)) |
| 468 | fn = DOC_DIR("materialliste"); |
| 469 | if (file_size(fn) >= 0) { |
| 470 | printf("Datei %s existiert bereits, loesche sie\n", fn); |
| 471 | rm(fn); |
| 472 | } |
| 473 | if (write_file(fn, "Material Liste\n==============\n\n")) { |
| 474 | dump_material(fn); |
| 475 | write_file(fn, gen_doc_foot("materialgruppen")); |
| 476 | printf("Materialliste erfolgreich in Datei %s geschrieben\n", fn); |
| 477 | } else |
| 478 | printf("Konnte Liste nicht in Datei %s schreiben, Abbruch\n", fn); |
| 479 | } |
| 480 | } |
| 481 | |
| 482 | /* GenMatGroupList |
| 483 | * |
| 484 | * Generiert Datei mit registrierten Materialgruppen fuer die Dokumentation, |
| 485 | */ |
| 486 | varargs void GenMatGroupList(string fn) |
| 487 | { |
| 488 | if (initialized) { |
| 489 | string txt; |
| 490 | if (!stringp(fn) || !sizeof(fn)) |
| 491 | fn = DOC_DIR("materialgruppen"); |
| 492 | if (file_size(fn) >= 0) { |
| 493 | printf("Datei %s existiert bereits, loesche sie\n", fn); |
| 494 | rm(fn); |
| 495 | } |
| 496 | if (write_file(fn, "Materialgruppen\n===============\n")) { |
| 497 | map(sort_array(m_indices(material_groups), #'>), #'dump_group, fn); |
| 498 | write_file(fn, gen_doc_foot("materialliste")); |
| 499 | printf("Materialliste erfolgreich in Datei %s geschrieben\n", fn); |
| 500 | } else |
| 501 | printf("Konnte Liste nicht in Datei %s schreiben, Abbruch\n", fn); |
| 502 | } |
| 503 | } |
| 504 | |
| 505 | /* GenHeaderFile |
| 506 | * |
| 507 | * Generiert Headerfile mit Definitionen der moeglichen Materialien und |
| 508 | * Gruppen |
| 509 | */ |
| 510 | varargs void GenHeaderFile(string fn) |
| 511 | { |
| 512 | if (initialized) { |
| 513 | string txt; |
| 514 | if (!stringp(fn) || !sizeof(fn)) |
| 515 | fn = HEADERFILE; |
| 516 | if (file_size(fn) >= 0) { |
| 517 | printf("Datei %s existiert bereits, loesche sie\n", fn); |
| 518 | rm(fn); |
| 519 | } |
| 520 | if (dump_material_h(fn)) |
| 521 | printf("Headerdatei erfolgreich in %s geschrieben\n", fn); |
| 522 | else |
| 523 | printf("Konnte Headerdatei nicht in Datei %s schreiben, Abbruch\n", fn); |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | //==================== Pruef- und Hilfsfunktionen fuer Materialien |
| 528 | private void updateGroupMembers(mapping groups, string mat_id, mapping mat) { |
| 529 | mixed *addgrps; // Array zum Ableiten von Gruppenzugehoerigkeiten |
| 530 | string *h; |
| 531 | int i, val; |
| 532 | mapping fractions; // Mapping mit Anteilen an Gruppen |
| 533 | fractions = mat[P_MG_FRACTIONS]; |
| 534 | if (!mappingp(fractions)) |
| 535 | fractions = ([]); |
| 536 | addgrps=({ // Reihenfolge wird rueckwaerts abgearbeitet |
| 537 | // Ableitungen sind z.T. abenteuerlich gewesen, mal ordentlich |
| 538 | // ausmisten. Die Zugehoerigkeit gehoert explizit in die |
| 539 | // Materialdefinition |
| 540 | // Gase sieht man normalerweise nicht: |
| 541 | ({"MATGROUP_INVIS", "MATGROUP_GAS"}), |
| 542 | // Mineralien sind auch Steine |
| 543 | ({"MATGROUP_STONE","MATGROUP_MINERAL"}), |
| 544 | // Edelmetalle sind Metalle: |
| 545 | ({"MATGROUP_METAL","MATGROUP_PRECIOUS_METAL"}), |
| 546 | // Lebewesen und deren Ueberreste, Paiere und Stoffe sind biologisch |
| 547 | ({"MATGROUP_BIO","MATGROUP_LIVING","MATGROUP_DEAD", |
| 548 | "MATGROUP_PAPER"}), |
| 549 | // Holz ist pflanzlich: |
| 550 | ({"MATGROUP_HERBAL", "MATGROUP_WOOD"}), |
| 551 | // Holz ist meistens tot: |
| 552 | ({"MATGROUP_DEAD","MATGROUP_WOOD"}), |
| 553 | // Holz, Papier und Stoffe brennen: |
| 554 | ({"MATGROUP_INFLAMMABLE","MATGROUP_WOOD","MATGROUP_PAPER"}), |
| 555 | // Laubhoelzer, Nadelhoelzer und Tropenhoelzer sind Holz |
| 556 | ({"MATGROUP_WOOD","MATGROUP_TROPICAL_WOOD","MATGROUP_DECIDUOUS_WOOD", |
| 557 | "MATGROUP_CONIFER_WOOD"}), |
| 558 | // Explosive Dinge sind immer entzuendlich: |
| 559 | ({"MATGROUP_INFLAMMABLE","MATGROUP_EXPLOSIVE"}) |
| 560 | }); |
| 561 | i=sizeof(addgrps); |
| 562 | while(i--) { |
| 563 | int j; |
| 564 | h=addgrps[i]; |
| 565 | if (member(fractions,h[0])) // Existiert schon eigener Eintrag? |
| 566 | continue; // Automatische Eintragung unnoetig |
| 567 | val=0; |
| 568 | for (j=sizeof(h)-1;j>=1;j--) |
| 569 | val+=fractions[h[j]]; |
| 570 | if (!val) |
| 571 | continue; |
| 572 | if (val>100) |
| 573 | val=100; |
| 574 | else if (val<-100) |
| 575 | val=-100; |
| 576 | fractions[h[0]]=val; |
| 577 | } |
| 578 | if (fractions["MATGROUP_LIVING"]) // Im Falle von lebendem Holz, tot loeschen |
| 579 | m_delete(fractions,"MATGROUP_DEAD"); |
| 580 | // Alles, was nicht als gasfoerming, fluessig oder fest eingeordnet ist, ist |
| 581 | // sonstwas: |
| 582 | if (!member(fractions, "MATGROUP_FLUID") |
| 583 | && !member(fractions, "MATGROUP_GAS") |
| 584 | && !member(fractions, "MATGROUP_SOLID")) |
| 585 | fractions["MATGROUP_MISC"]=100; |
| 586 | // Materialien als Mitglieder in die Gruppen eintragen |
| 587 | addgrps=m_indices(fractions); |
| 588 | i=sizeof(addgrps); |
| 589 | while(i--) { |
| 590 | mixed ind; |
| 591 | ind=addgrps[i]; |
| 592 | if (!fractions[ind] || !member(groups, ind)) { |
| 593 | // Unbekannte Gruppe und Gruppe ohne Anteil aus Mapping loeschen |
| 594 | m_delete(fractions,ind); |
| 595 | continue; |
| 596 | } |
| 597 | if (!pointerp(h=groups[ind][P_MEMBERS])) |
| 598 | h=({}); |
| 599 | h+=({mat_id}); |
| 600 | groups[ind][P_MEMBERS]=h; |
| 601 | } |
| 602 | mat[P_MG_FRACTIONS] = fractions; |
| 603 | } |
| 604 | |
| 605 | //==================== Einlesen der Mappings aus Dateien |
| 606 | |
| 607 | #define MDESC_ERROR(x, y) LOG_ERROR(sprintf("Materialbeschreibung '%s': %s\n", x, y)) |
| 608 | #define MDESC_WARN(x, y) //LOG_WARN(sprintf("Materialbeschreibung '%s': %s\n", x, y)) |
| 609 | |
| 610 | private mapping getDescParts(string s) { |
| 611 | string* lines; |
| 612 | string key, val; |
| 613 | int i, n; |
| 614 | mapping m; |
| 615 | m = ([]); |
| 616 | val = ""; |
| 617 | lines = explode(s, "\n"); |
| 618 | n = sizeof(lines); |
| 619 | if (n > 0) { |
| 620 | while (i < n) { |
| 621 | if (sscanf(lines[i], "%s:", key)) { |
| 622 | status multiline; |
| 623 | multiline = 0; |
| 624 | // Schluessel gefunden, Wert auslesen |
| 625 | while ( (++i < n) && sizeof(lines[i])) { |
| 626 | // Mehrzeilige Werte mit newline verketten |
| 627 | if (multiline) { |
| 628 | val += "\n"; |
| 629 | } |
| 630 | val += lines[i]; |
| 631 | multiline = 1; |
| 632 | } |
| 633 | m += ([key:val]); |
| 634 | val = ""; |
| 635 | } |
| 636 | i++; |
| 637 | } |
| 638 | } |
| 639 | return m; |
| 640 | } |
| 641 | private varargs int isFile(string fn, string path) { |
| 642 | if (stringp(path) && sizeof(path)) |
| 643 | fn = path+"/"+fn; |
| 644 | return (file_size(fn) >= 0); |
| 645 | } |
| 646 | |
| 647 | private varargs mixed readGroupDesc(string id) { |
| 648 | mixed m; |
| 649 | string fn; |
| 650 | fn = MAT_DIR+"/groups/"+id; |
| 651 | if (file_size(fn) > 0) { |
| 652 | mapping parts; |
| 653 | string desc; |
| 654 | parts = getDescParts(read_file(fn)); |
| 655 | m = ([P_NAME:parts["Name"], |
| 656 | P_MEMBERS:({})]); |
| 657 | if (member(parts,"Beschreibung")) |
| 658 | m += ([P_DESCRIPTION:parts["Beschreibung"]]); |
| 659 | if (parts["Gruppenid"] != id) |
| 660 | LOG_WARN(sprintf("Unstimmigkeit Gruppenid bei '%s'\n", id)); |
| 661 | } else { |
| 662 | LOG_ERROR(sprintf("Kann Gruppenbeschreibung %s nicht laden\n", fn)); |
| 663 | } |
| 664 | return m; |
| 665 | } |
| 666 | |
| 667 | private mapping convMatId(string s) { |
| 668 | mapping m; |
| 669 | string* parts; |
| 670 | parts = explode(s, "\""); |
| 671 | if (sizeof(parts)) { |
| 672 | int ende; |
| 673 | ende = strstr(parts[0]," ")-1; |
| 674 | if (ende < 0) |
| 675 | ende = sizeof(parts[0]); |
| 676 | m = ([P_ID:parts[0][0..ende]]); |
| 677 | if (sizeof(parts) > 1) |
| 678 | m += ([P_DEFSTR:parts[1]]); |
| 679 | } |
| 680 | return m; |
| 681 | } |
| 682 | private string* convMatNames(string s) { |
| 683 | string* names; |
| 684 | names = filter(explode(s, "\""), |
| 685 | lambda( ({'x}), ({#'>, ({#'sizeof, 'x}), 1}) )); |
| 686 | if (sizeof(names)<1) |
| 687 | names=0; |
| 688 | else { |
| 689 | if (sizeof(names)<2) |
| 690 | names+=({names[0]+"s"}); |
| 691 | if (sizeof(names)<3) |
| 692 | names+=({names[0]}); |
| 693 | if (sizeof(names)<4) |
| 694 | names+=({names[0]}); |
| 695 | } |
| 696 | return names; |
| 697 | } |
| 698 | private int convMatGender(string s) { |
| 699 | int gender; |
| 700 | s = lowerstring(s); |
| 701 | // Ein Buchstabe reicht zur Bestimmung. Wenn nur weiblich|female |
| 702 | // bzw. maennlich|male verwendet wird. Dabei ist dann allerdings die |
| 703 | // Reihenfolge der Auswertung wichtig, damit das m bei MALE nicht mehr bei |
| 704 | // female passt. |
| 705 | if (sizeof(regexp( ({s}), "f|w"))) { |
| 706 | gender = FEMALE; |
| 707 | } else if (sizeof(regexp( ({s}), "m"))) { |
| 708 | gender = MALE; |
| 709 | } else { |
| 710 | gender = NEUTER; |
| 711 | } |
| 712 | return gender; |
| 713 | } |
| 714 | private string convMatDesc(string s) { |
| 715 | if (sizeof(regexp( ({s}), "- nicht vorhanden -"))) { |
| 716 | s = 0; |
| 717 | } else { |
| 718 | // Mehrzeilige Beschreibungen zu einer Zeile zusammenfassen |
| 719 | s = implode(explode(s, "\n"), " "); |
| 720 | } |
| 721 | return s; |
| 722 | } |
| 723 | private void addRecocLine(string s, mixed* r) { |
| 724 | // Die weitere Bewertung der Schwierigkeit kann erst vorgenommen werden, |
| 725 | // wenn alle Materialien bekannt sind und passiert spaeter. Zuerst werden |
| 726 | // nur die Elemente des Arrays konvertiert und eingetragen |
| 727 | string mat; |
| 728 | int val; |
| 729 | if (sscanf(s, "%s:%d", mat, val)) { |
| 730 | r += ({mat,val}); |
| 731 | } else if (sscanf(s, "%d", val)) { |
| 732 | r += ({val}); |
| 733 | } else { |
| 734 | r += ({s}); |
| 735 | } |
| 736 | } |
| 737 | private mixed convMatRec(string s) { |
| 738 | mixed difficulties; |
| 739 | if (sizeof(regexp( ({s}), "- keine Einschraenkung -"))) { |
| 740 | difficulties = 0; |
| 741 | } else { |
| 742 | difficulties = ({}); |
| 743 | // Jede Zeile enthaelt eine Bedingung |
| 744 | map(explode(s, "\n"), #'addRecocLine, &difficulties); |
| 745 | } |
| 746 | return difficulties; |
| 747 | } |
| 748 | private void addGroupLine(string s, mapping g) { |
| 749 | // Die weitere Bewertung der Zugehoerigkeit passiert spaeter. |
| 750 | string grp; |
| 751 | int val; |
| 752 | if (sscanf(s, "%s:%d", grp, val)) { |
| 753 | g += ([grp:val]); |
| 754 | } else { |
| 755 | g += ([grp:100]); |
| 756 | } |
| 757 | } |
| 758 | private mapping convMatGroups(string s) { |
| 759 | mapping groups; |
| 760 | if (!sizeof(regexp( ({s}), "- keine -"))) { |
| 761 | groups = ([]); |
| 762 | // Jede Zeile enthaelt eine Bedingung |
| 763 | map(explode(s, "\n"), #'addGroupLine, groups); |
| 764 | } |
| 765 | return groups; |
| 766 | } |
| 767 | private mapping convMaterialDesc(string id, mapping desc) { |
| 768 | /* Struktur Materialmapping: |
| 769 | P_GENDER, |
| 770 | P_NAME:({name_nom, name_gen, name_dativ, name_akkusativ}), |
| 771 | (P_RECOC:({mat1,faehigkeit1,mat2,faehigkeit2,...}),) |
| 772 | (P_DEFSTR: bei bedarf), |
| 773 | P_DESCRIPTION, |
| 774 | (grupp1:anteil1, |
| 775 | gruppe2:anteil2, |
| 776 | ...) |
| 777 | */ |
| 778 | mapping m; |
| 779 | mixed val, val2; |
| 780 | m = ([]); |
| 781 | // Der string fuer das #define zuerst: |
| 782 | val = convMatId(desc["Materialid"]); |
| 783 | if (mappingp(val)) { |
| 784 | if (val[P_ID] != id) |
| 785 | LOG_WARN(sprintf("Unstimmigkeit Materialid bei '%s':%O\n", id, val[P_ID])); |
| 786 | if (member(val, P_DEFSTR)) { |
| 787 | m += ([P_DEFSTR:val[P_DEFSTR]]); |
| 788 | } else { |
| 789 | // Wenn kein String fuers #define angegeben wurde, dann direkt ID verwenden |
| 790 | //m += ([P_DEFSTR:lowerstring(id)[4..]]); |
| 791 | } |
| 792 | } |
| 793 | // Die Namen |
| 794 | if (val = convMatNames(desc["Name"])) { |
| 795 | m += ([P_NAME:val]); |
| 796 | } else { |
| 797 | MDESC_WARN(id, "keine Namen"); |
| 798 | m += ([P_NAME:({"", "", "", ""})]); |
| 799 | } |
| 800 | // Das Geschlecht, standard ist NEUTER |
| 801 | m += ([P_GENDER:convMatGender(desc["Geschlecht"]) ]); |
| 802 | // Die Beschreibung |
| 803 | val = convMatDesc(desc["Beschreibung"]); |
| 804 | if (sizeof(val)) { |
| 805 | m += ([P_DESCRIPTION:val]); |
| 806 | } else { |
| 807 | MDESC_WARN(id, "keine Beschreibung"); |
| 808 | } |
| 809 | // Die Erkennbarkeit |
| 810 | val = convMatRec(desc["Erkennbarkeit"]); |
| 811 | if (sizeof(val)) { |
| 812 | m += ([P_RECOC:val]); |
| 813 | } |
| 814 | // und zum Schluss die Gruppenzugehoerigkeit |
| 815 | val = convMatGroups(desc["Gruppenzugehoerigkeit"]); |
| 816 | if (mappingp(val) && sizeof(val)) { |
| 817 | m += ([P_MG_FRACTIONS:val]); |
| 818 | } |
| 819 | return m; |
| 820 | } |
| 821 | private varargs mixed readMaterialDesc(string id) { |
| 822 | mixed m; |
| 823 | string fn; |
| 824 | fn = MAT_DIR+"/materials/"+id; |
| 825 | if (file_size(fn) > 0) { |
| 826 | mapping parts; |
| 827 | string desc; |
| 828 | parts = getDescParts(read_file(fn)); |
| 829 | m = convMaterialDesc(id, parts); |
| 830 | } else { |
| 831 | LOG_ERROR(sprintf("MDB:Kann Materialbeschreibung %s nicht laden\n", fn)); |
| 832 | } |
| 833 | return m; |
| 834 | } |
| 835 | |
| 836 | public int GetUpdateTicks() { |
| 837 | return updateTicks; |
| 838 | } |
| 839 | |
| 840 | private void scanFinished() { |
| 841 | isScanning = 0; |
| 842 | initialized = 1; |
| 843 | // Mappings umkopieren |
| 844 | materials = new_materials; |
| 845 | material_groups = new_material_groups; |
| 846 | // Letzter Schritt: Mapping mit alten Schluesseln anlegen |
| 847 | old_mat_keys = mkmapping(map(m_indices(materials), #'matKey2Defstr, materials), |
| 848 | m_indices(materials)); |
| 849 | // Generieren der Doku und des Materialheaders |
| 850 | GenHeaderFile(); |
| 851 | GenMatList(); |
| 852 | GenMatGroupList(); |
| 853 | // Savefile schreiben |
| 854 | save_object(SAVEFILE); |
| 855 | } |
| 856 | |
| 857 | public int IsScanning() { |
| 858 | return isScanning; |
| 859 | } |
| 860 | |
| 861 | private varargs void doScanMaterials(string* mats, int i, int step) { |
| 862 | int ticks, start; |
| 863 | string matid; |
| 864 | start = get_eval_cost(); |
| 865 | if (step < 2) { |
| 866 | while ( (i < sizeof(mats)) && |
| 867 | ((start - get_eval_cost()) < query_limits()[LIMIT_EVAL]/3 ) ) { |
| 868 | matid = mats[i]; |
| 869 | switch (step) { |
| 870 | case 0: |
| 871 | // Erster Schritt: Einlesen der Dateien |
| 872 | new_materials[matid] = readMaterialDesc(matid); |
| 873 | break; |
| 874 | case 1: |
| 875 | // Zweiter Schritt: Bearbeiten der Erkennung und Gruppenzugehoerigkeit |
| 876 | updateGroupMembers(new_material_groups, matid, new_materials[matid]); |
| 877 | break; |
| 878 | default: |
| 879 | break; |
| 880 | } |
| 881 | i++; |
| 882 | } |
| 883 | } |
| 884 | if (i < sizeof(mats)) { |
| 885 | catch(raise_error(sprintf("MaterialDB: Initialisierung noch nicht beendet," |
| 886 | " fehlende Materialbeschreibungen moeglich" |
| 887 | " (Phase %d:%d/%d)\n", |
| 888 | step, i, sizeof(mats)));publish); |
| 889 | call_out(#'doScanMaterials, 2, mats, i, step); |
| 890 | } else { |
| 891 | // Zweite Stufe ausloesen oder beenden |
| 892 | if (step < 1) { |
| 893 | if ((start - get_eval_cost()) < query_limits()[LIMIT_EVAL]/2 ) |
| 894 | doScanMaterials(mats, 0, step+1); |
| 895 | else |
| 896 | call_out(#'doScanMaterials, 2, mats, 0, step+1); |
| 897 | } |
| 898 | else |
| 899 | scanFinished(); |
| 900 | } |
| 901 | updateTicks += start - get_eval_cost(); |
| 902 | } |
| 903 | |
| 904 | private mapping ScanGroups() { |
| 905 | mapping groups; |
| 906 | string* grpfiles; |
| 907 | groups = ([]); |
| 908 | grpfiles = filter(get_dir(MAT_DIR+"/groups/MATGROUP_*"), |
| 909 | #'isFile, MAT_DIR+"/groups"); |
| 910 | groups = mkmapping(grpfiles, map(grpfiles, #'readGroupDesc, 1)); |
| 911 | return groups; |
| 912 | } |
| 913 | |
| 914 | private void ScanMaterials() { |
| 915 | string *matfiles; |
| 916 | matfiles = filter(get_dir(MAT_DIR+"/materials/MAT_*"), |
| 917 | #'isFile, MAT_DIR+"/materials"); |
| 918 | doScanMaterials(matfiles); |
| 919 | } |
| 920 | |
| 921 | void Update() { |
| 922 | int start; |
| 923 | updateTicks = 0; |
| 924 | start = get_eval_cost(); |
| 925 | if (!isScanning) { |
| 926 | if (sizeof(get_dir(MAT_DIR))) { |
| 927 | isScanning = 1; |
| 928 | new_material_groups = ScanGroups(); |
| 929 | new_materials = ([]); |
| 930 | updateTicks = start - get_eval_cost(); |
| 931 | ScanMaterials(); |
| 932 | } else { |
| 933 | LOG_ERROR("Kann Materialverzeichnis nicht finden, keine Materialien angelegt!\n"); |
| 934 | } |
| 935 | } |
| 936 | } |