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