blob: a1240a8f3aefdc9844577345293562eb37dde7d3 [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;
Zesstrabe894b42019-11-27 19:56:32 +0100150 mixed tmp, x;
MG Mud User88f12472016-06-24 23:31:02 +0200151
152 recval=0;
Zesstrabe894b42019-11-27 19:56:32 +0100153 mapping grps=props[P_MG_FRACTIONS];
MG Mud User88f12472016-06-24 23:31:02 +0200154 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 }
Arathornb3051452021-05-13 21:13:03 +0200219 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200220}
221
222varargs string ConvMaterialList(mixed mats, int casus, mixed idinf) {
223 if (initialized) {
224 string *ms,ml;
225 int i;
226
227 ml="";
228 if (mappingp(mats))
229 ms=m_indices(mats);
230 else if (stringp(mats))
231 ms=({mats});
232 else if (pointerp(mats))
233 ms=mats;
234 else
235 ms=({});
236 i=sizeof(ms);
237 while(i) {
238 ml+=MaterialName(ms[--i],casus,idinf);
239 if (i)
240 ml+=((i>1)?", ":" und ");
241 }
242 return ml;
243 }
Arathornb3051452021-05-13 21:13:03 +0200244 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200245}
246
247int MaterialGroup(mapping mats, string grp) {
248 if (initialized) {
249 string *ms;
250 int i,res;
251
252 res=0;
253 if (!mappingp(mats) || !stringp(grp))
254 return res;
255 ms=m_indices(mats);
256 i=sizeof(ms);
257 while(i--) {
258 string mat;
259 mapping props;
260 mat=ms[i];
261 if (mappingp(props=materials[getMatId(mat)]))
262 res+=(mats[mat]*props[P_MG_FRACTIONS][getMatGroupId(grp)])/100;
263 }
264 if (res<-100) // Vielleicht noch Antimaterie zulassen
265 res=-100; // (noch nicht sicher ob das so bleiben wird oder 0 sein wird)
266 if (res>100)
267 res=100;
268 return res;
269 }
Arathornb3051452021-05-13 21:13:03 +0200270 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200271}
272
273string *AllMaterials() {
274 if (initialized) {
275 // Aus Kompatibilitaetsgruenden die alten Schluessel (#define-String)
276 // zurueckgeben
277 return m_indices(old_mat_keys);
278 }
279 return 0;
280}
281
282string *AllGroups() {
283 if (initialized) {
284 // Aus Kompatibilitaetsgruenden die alten Schluessel (#define-String)
285 // zurueckgeben
286 return map(m_indices(material_groups), #'groupKey2Defstr);
287 }
288 return 0;
289}
290
291string *GetMatMembership(string mat) {
292 if (initialized) {
293 mapping props;
294 // Anpassen der Materialid
295 mat = getMatId(mat);
296
297 if (!mappingp(props=materials[mat]))
298 return ({});
299 return map(m_indices(props[P_MG_FRACTIONS]), #'groupKey2Defstr);
300 }
301 return 0;
302}
303
304string *GetGroupMembers(string grp) {
305 if (initialized) {
306 string *mats;
307 // Anpassen der Materialid
308 grp = getMatGroupId(grp);
309 if (!member(material_groups, grp) ||
310 !pointerp(mats=material_groups[grp][P_MEMBERS]))
311 return ({});
312 return map(mats, #'matKey2Defstr, materials);
313 }
314 return 0;
315}
316
317string GroupName(string grp) {
318 if (initialized) {
319 if (member(material_groups, getMatGroupId(grp)))
320 return material_groups[getMatGroupId(grp)][P_NAME];
321 else
322 return "Unbekanntes";
323 }
Arathornb3051452021-05-13 21:13:03 +0200324 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200325}
326
327string GroupDescription(string grp) {
328 if (initialized) {
329 if (member(material_groups, getMatGroupId(grp)))
330 return material_groups[getMatGroupId(grp)][P_DESCRIPTION];
331 else
332 return "Gruppe unbekannt";
333 }
Arathornb3051452021-05-13 21:13:03 +0200334 return 0;
MG Mud User88f12472016-06-24 23:31:02 +0200335}
336
337//==================== Generieren von Headerfile und Manpages
338private string *get_ordered_groups()
339{
340 return ({"MATGROUP_WOOD", "MATGROUP_JEWEL", "MATGROUP_STONE", "MATGROUP_MAGNETIC",
341 "MATGROUP_METAL", "MATGROUP_DRUG", "MATGROUP_HERBAL", "MATGROUP_FLEXIBLE",
342 "MATGROUP_BIO", "MATGROUP_ACIDIC", "MATGROUP_BASIC", "MATGROUP_POISONOUS",
343 "MATGROUP_EXPLOSIVE", "MATGROUP_INFLAMMABLE",
344 "MATGROUP_ELEMENTAL", "MATGROUP_ELECTRICAL", "MATGROUP_MAGIC",
345 "MATGROUP_HOLY", "MATGROUP_UNHOLY", "MATGROUP_INVIS",
346 "MATGROUP_SOLID", "MATGROUP_FLUID", "MATGROUP_GAS"});
347}
348private string gen_material_h_head()
349{
350 return
351 "// MorgenGrauen MUDlib\n//\n"
352 "// materials.h -- material definitions\n//\n"
353 "// This file is generated by /secure/materialdb.c\n//\n"
354 "// DO NOT EDIT!\n//\n"
355 "// $Id: materialdb.c 8755 2014-04-26 13:13:40Z Zesstra $\n\n"
356 "#ifndef __MATERIALS_H__\n"
357 "#define __MATERIALS_H__\n\n";
358}
359private string gen_material_h_material(string mat, string last_grp)
360{
361 mat = old_mat_keys[mat];
362 return sprintf("#define %-24s\"%-20s // %s\n", mat,
363 (member(materials[mat], P_DEFSTR)?materials[mat][P_DEFSTR]:mat)+"\"",
364 materials[mat][P_DESCRIPTION]||materials[mat][P_NAME][WER]);
365}
366private string gen_material_h_materials_grp(string grp, string *left)
367{
368 string txt, *mats;
369 txt = sprintf("\n// Gruppe: %s\n", GroupName(grp));
370 mats = GetGroupMembers(grp) - (GetGroupMembers(grp) - left);
371 txt += sprintf("%@s", map(sort_array(mats, #'>), #'gen_material_h_material));
372 left -= GetGroupMembers(grp);
373 return txt;
374}
375private string gen_material_h_materials()
376{
Arathornb3051452021-05-13 21:13:03 +0200377 string txt;
MG Mud User88f12472016-06-24 23:31:02 +0200378 string *grps, *mats;
379 txt = "// ****************************** Materialien ******************************\n";
380 // Gruppenweise ordnen
381 grps = get_ordered_groups();
382 mats = AllMaterials();
383 txt += sprintf("%@s", map(grps, #'gen_material_h_materials_grp,
384 &mats));
Zesstra9ad254c2019-09-27 00:30:41 +0200385 // Uebriggebliene Materialien ausgeben
MG Mud User88f12472016-06-24 23:31:02 +0200386 txt += "// sonstige Materialien:\n";
387 txt += sprintf("%@s", map(mats, #'gen_material_h_material));
388 return txt;
389}
390private string gen_material_h_group(string grp)
391{
392 return sprintf("#define %-27s\"%-18s // %s\n",
393 grp, groupKey2Defstr(grp)+"\"", GroupName(grp));
394}
395private string gen_material_h_groups()
396{
397 string txt;
398 txt = "\n// **************************** Materialgruppen ****************************\n\n"
399 "#ifndef _IS_MATERIALDB_\n";
400 txt += sprintf("%@s\n", map(sort_array(m_indices(material_groups), #'>),
401 #'gen_material_h_group));
402 txt += "\n#endif // _IS_MATERIALDB_\n";
403 return txt;
404}
405private string gen_material_h_foot()
406{
407 return
408 "#endif // __THING_MATERIAL_H__\n";
409}
410private int dump_material_h(string fn)
411{
412 return (write_file(fn, gen_material_h_head()) &&
413 write_file(fn, gen_material_h_materials()) &&
414 write_file(fn, gen_material_h_groups()) &&
415 write_file(fn, gen_material_h_foot()));
416}
417private string gen_material_list_material(string mat)
418{
419 mat = old_mat_keys[mat];
420 return sprintf(" %-28s%=-45s\n", mat,
421 materials[mat][P_DESCRIPTION]||materials[mat][P_NAME][WER]);
422}
423private string gen_material_list_materials_grp(string grp, string *left)
424{
425 string txt, *mats;
426 txt = sprintf("%s:\n", capitalize(GroupName(grp)));
427 mats = sort_array(GetGroupMembers(grp) - (GetGroupMembers(grp) - left), #'>);
428 txt += sprintf("%@s\n", map(mats, #'gen_material_list_material));
429 left -= GetGroupMembers(grp);
430 return txt;
431}
432private void dump_material(string fn)
433{
434 string txt;
435 string *grps, *mats;
436 // Gruppenweise ordnen
437 grps = get_ordered_groups();
438 mats = AllMaterials();
439 txt = sprintf("%@s", map(grps, #'gen_material_list_materials_grp,
440 &mats));
Zesstra9ad254c2019-09-27 00:30:41 +0200441 // Uebriggebliene Materialien ausgeben
MG Mud User88f12472016-06-24 23:31:02 +0200442 txt += "sonstige Materialien:\n";
443 txt += sprintf("%@s", map(mats, #'gen_material_list_material));
444 write_file(fn, txt) ||
445 raise_error(sprintf("Konnte Liste nicht weiter in Datei %s schreiben,"
446 " Abbruch\n", fn));
447}
448private void dump_group(string grp, string fn)
449{
450 // upperstring langsame simul_efun, warum?
451 write_file(fn, sprintf(" %-28s%=-48s\n", (grp),
452 GroupName(grp))) ||
453 raise_error(sprintf("Konnte Liste nicht weiter in Datei %s schreiben,"
454 " Abbruch\n", fn));
455}
456private string gen_doc_foot(string other)
457{
458 return sprintf("\nSIEHE AUCH:\n"
459 " Konzepte: material, materialerkennung\n"
460 " Grundlegend: P_MATERIAL, /sys/materials.h, /sys/thing/material.h\n"
461 " Methoden: QueryMaterial(), QueryMaterialGroup(), MaterialList(),\n"
462 " Listen: AllMaterials(), AllGroups()\n"
463 " %s\n"
464 " Master: ConvMaterialList(), MaterialGroup(),\n"
465 " GroupName(), MaterialName(),\n"
466 " GetGroupMembers(), GetMatMembership()\n"
467 " Sonstiges: P_MATERIAL_KNOWLEDGE\n\n"
468 "%s generiert aus /secure/materialdb\n", other, dtime(time()));
469}
470
471/* GenMatList
472 *
473 * Generiert Datei mit registrierten Materialien fuer die Dokumentation,
474 */
475varargs void GenMatList(string fn)
476{
477 if (initialized) {
MG Mud User88f12472016-06-24 23:31:02 +0200478 if (!stringp(fn) || !sizeof(fn))
479 fn = DOC_DIR("materialliste");
480 if (file_size(fn) >= 0) {
Zesstrad77ab422019-09-27 17:39:27 +0200481 debug_message(
482 sprintf("Datei %s existiert bereits, loesche sie\n", fn),
483 DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200484 rm(fn);
485 }
Zesstrad77ab422019-09-27 17:39:27 +0200486 if (write_file(fn, "Material Liste\n==============\n\n"))
487 {
MG Mud User88f12472016-06-24 23:31:02 +0200488 dump_material(fn);
489 write_file(fn, gen_doc_foot("materialgruppen"));
Zesstrad77ab422019-09-27 17:39:27 +0200490 debug_message(
491 sprintf("Materialliste erfolgreich in Datei %s geschrieben\n", fn),
492 DMSG_STAMP);
493 }
494 else
495 debug_message(
496 sprintf("Konnte Liste nicht in Datei %s schreiben, Abbruch\n", fn),
497 DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200498 }
499}
500
501/* GenMatGroupList
502 *
503 * Generiert Datei mit registrierten Materialgruppen fuer die Dokumentation,
504 */
505varargs void GenMatGroupList(string fn)
506{
507 if (initialized) {
MG Mud User88f12472016-06-24 23:31:02 +0200508 if (!stringp(fn) || !sizeof(fn))
509 fn = DOC_DIR("materialgruppen");
510 if (file_size(fn) >= 0) {
Zesstrad77ab422019-09-27 17:39:27 +0200511 debug_message(
512 sprintf("Datei %s existiert bereits, loesche sie\n", fn),
513 DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200514 rm(fn);
515 }
Zesstrad77ab422019-09-27 17:39:27 +0200516 if (write_file(fn, "Materialgruppen\n===============\n"))
517 {
MG Mud User88f12472016-06-24 23:31:02 +0200518 map(sort_array(m_indices(material_groups), #'>), #'dump_group, fn);
519 write_file(fn, gen_doc_foot("materialliste"));
Zesstrad77ab422019-09-27 17:39:27 +0200520 debug_message(
521 sprintf("Materialliste erfolgreich in Datei %s geschrieben\n", fn),
522 DMSG_STAMP);
523 }
524 else
525 debug_message(
526 sprintf("Konnte Liste nicht in Datei %s schreiben, Abbruch\n", fn),
527 DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200528 }
529}
530
531/* GenHeaderFile
532 *
533 * Generiert Headerfile mit Definitionen der moeglichen Materialien und
534 * Gruppen
535 */
536varargs void GenHeaderFile(string fn)
537{
538 if (initialized) {
MG Mud User88f12472016-06-24 23:31:02 +0200539 if (!stringp(fn) || !sizeof(fn))
540 fn = HEADERFILE;
Zesstrad77ab422019-09-27 17:39:27 +0200541 if (file_size(fn) >= 0)
542 {
543 debug_message(
544 sprintf("Datei %s existiert bereits, loesche sie\n", fn),
545 DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200546 rm(fn);
547 }
548 if (dump_material_h(fn))
Zesstrad77ab422019-09-27 17:39:27 +0200549 debug_message(
550 sprintf("Headerdatei erfolgreich in %s geschrieben\n", fn),
551 DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200552 else
Zesstrad77ab422019-09-27 17:39:27 +0200553 debug_message(
554 sprintf("Konnte Headerdatei nicht in Datei %s schreiben, Abbruch\n",
555 fn), DMSG_STAMP);
MG Mud User88f12472016-06-24 23:31:02 +0200556 }
557}
558
559//==================== Pruef- und Hilfsfunktionen fuer Materialien
560private void updateGroupMembers(mapping groups, string mat_id, mapping mat) {
561 mixed *addgrps; // Array zum Ableiten von Gruppenzugehoerigkeiten
562 string *h;
563 int i, val;
564 mapping fractions; // Mapping mit Anteilen an Gruppen
565 fractions = mat[P_MG_FRACTIONS];
566 if (!mappingp(fractions))
567 fractions = ([]);
568 addgrps=({ // Reihenfolge wird rueckwaerts abgearbeitet
569 // Ableitungen sind z.T. abenteuerlich gewesen, mal ordentlich
570 // ausmisten. Die Zugehoerigkeit gehoert explizit in die
571 // Materialdefinition
572 // Gase sieht man normalerweise nicht:
573 ({"MATGROUP_INVIS", "MATGROUP_GAS"}),
574 // Mineralien sind auch Steine
575 ({"MATGROUP_STONE","MATGROUP_MINERAL"}),
576 // Edelmetalle sind Metalle:
577 ({"MATGROUP_METAL","MATGROUP_PRECIOUS_METAL"}),
578 // Lebewesen und deren Ueberreste, Paiere und Stoffe sind biologisch
579 ({"MATGROUP_BIO","MATGROUP_LIVING","MATGROUP_DEAD",
580 "MATGROUP_PAPER"}),
581 // Holz ist pflanzlich:
582 ({"MATGROUP_HERBAL", "MATGROUP_WOOD"}),
583 // Holz ist meistens tot:
584 ({"MATGROUP_DEAD","MATGROUP_WOOD"}),
585 // Holz, Papier und Stoffe brennen:
586 ({"MATGROUP_INFLAMMABLE","MATGROUP_WOOD","MATGROUP_PAPER"}),
587 // Laubhoelzer, Nadelhoelzer und Tropenhoelzer sind Holz
588 ({"MATGROUP_WOOD","MATGROUP_TROPICAL_WOOD","MATGROUP_DECIDUOUS_WOOD",
589 "MATGROUP_CONIFER_WOOD"}),
590 // Explosive Dinge sind immer entzuendlich:
591 ({"MATGROUP_INFLAMMABLE","MATGROUP_EXPLOSIVE"})
592 });
593 i=sizeof(addgrps);
594 while(i--) {
595 int j;
596 h=addgrps[i];
597 if (member(fractions,h[0])) // Existiert schon eigener Eintrag?
598 continue; // Automatische Eintragung unnoetig
599 val=0;
600 for (j=sizeof(h)-1;j>=1;j--)
601 val+=fractions[h[j]];
602 if (!val)
603 continue;
604 if (val>100)
605 val=100;
606 else if (val<-100)
607 val=-100;
608 fractions[h[0]]=val;
609 }
610 if (fractions["MATGROUP_LIVING"]) // Im Falle von lebendem Holz, tot loeschen
611 m_delete(fractions,"MATGROUP_DEAD");
612 // Alles, was nicht als gasfoerming, fluessig oder fest eingeordnet ist, ist
613 // sonstwas:
614 if (!member(fractions, "MATGROUP_FLUID")
615 && !member(fractions, "MATGROUP_GAS")
616 && !member(fractions, "MATGROUP_SOLID"))
617 fractions["MATGROUP_MISC"]=100;
618 // Materialien als Mitglieder in die Gruppen eintragen
619 addgrps=m_indices(fractions);
620 i=sizeof(addgrps);
621 while(i--) {
622 mixed ind;
623 ind=addgrps[i];
624 if (!fractions[ind] || !member(groups, ind)) {
625 // Unbekannte Gruppe und Gruppe ohne Anteil aus Mapping loeschen
626 m_delete(fractions,ind);
627 continue;
628 }
629 if (!pointerp(h=groups[ind][P_MEMBERS]))
630 h=({});
631 h+=({mat_id});
632 groups[ind][P_MEMBERS]=h;
633 }
634 mat[P_MG_FRACTIONS] = fractions;
635}
636
637//==================== Einlesen der Mappings aus Dateien
638
639#define MDESC_ERROR(x, y) LOG_ERROR(sprintf("Materialbeschreibung '%s': %s\n", x, y))
640#define MDESC_WARN(x, y) //LOG_WARN(sprintf("Materialbeschreibung '%s': %s\n", x, y))
641
642private mapping getDescParts(string s) {
643 string* lines;
644 string key, val;
645 int i, n;
646 mapping m;
647 m = ([]);
648 val = "";
649 lines = explode(s, "\n");
650 n = sizeof(lines);
651 if (n > 0) {
652 while (i < n) {
653 if (sscanf(lines[i], "%s:", key)) {
654 status multiline;
655 multiline = 0;
656 // Schluessel gefunden, Wert auslesen
657 while ( (++i < n) && sizeof(lines[i])) {
658 // Mehrzeilige Werte mit newline verketten
659 if (multiline) {
660 val += "\n";
661 }
662 val += lines[i];
663 multiline = 1;
664 }
665 m += ([key:val]);
666 val = "";
667 }
668 i++;
669 }
670 }
671 return m;
672}
673private varargs int isFile(string fn, string path) {
674 if (stringp(path) && sizeof(path))
675 fn = path+"/"+fn;
676 return (file_size(fn) >= 0);
677}
678
679private varargs mixed readGroupDesc(string id) {
680 mixed m;
681 string fn;
682 fn = MAT_DIR+"/groups/"+id;
683 if (file_size(fn) > 0) {
684 mapping parts;
MG Mud User88f12472016-06-24 23:31:02 +0200685 parts = getDescParts(read_file(fn));
686 m = ([P_NAME:parts["Name"],
687 P_MEMBERS:({})]);
688 if (member(parts,"Beschreibung"))
689 m += ([P_DESCRIPTION:parts["Beschreibung"]]);
690 if (parts["Gruppenid"] != id)
691 LOG_WARN(sprintf("Unstimmigkeit Gruppenid bei '%s'\n", id));
692 } else {
693 LOG_ERROR(sprintf("Kann Gruppenbeschreibung %s nicht laden\n", fn));
694 }
695 return m;
696}
697
698private mapping convMatId(string s) {
699 mapping m;
700 string* parts;
701 parts = explode(s, "\"");
702 if (sizeof(parts)) {
703 int ende;
704 ende = strstr(parts[0]," ")-1;
705 if (ende < 0)
706 ende = sizeof(parts[0]);
707 m = ([P_ID:parts[0][0..ende]]);
708 if (sizeof(parts) > 1)
709 m += ([P_DEFSTR:parts[1]]);
710 }
711 return m;
712}
Zesstra077cbc62019-01-07 21:16:39 +0100713
MG Mud User88f12472016-06-24 23:31:02 +0200714private string* convMatNames(string s) {
Zesstra077cbc62019-01-07 21:16:39 +0100715 string* names = filter(explode(s, "\""), function int (string x) {
716 return sizeof(x)>1;
717 });
MG Mud User88f12472016-06-24 23:31:02 +0200718 if (sizeof(names)<1)
719 names=0;
720 else {
721 if (sizeof(names)<2)
722 names+=({names[0]+"s"});
723 if (sizeof(names)<3)
724 names+=({names[0]});
725 if (sizeof(names)<4)
726 names+=({names[0]});
727 }
728 return names;
729}
Zesstra077cbc62019-01-07 21:16:39 +0100730
MG Mud User88f12472016-06-24 23:31:02 +0200731private int convMatGender(string s) {
732 int gender;
733 s = lowerstring(s);
734 // Ein Buchstabe reicht zur Bestimmung. Wenn nur weiblich|female
735 // bzw. maennlich|male verwendet wird. Dabei ist dann allerdings die
736 // Reihenfolge der Auswertung wichtig, damit das m bei MALE nicht mehr bei
737 // female passt.
738 if (sizeof(regexp( ({s}), "f|w"))) {
739 gender = FEMALE;
740 } else if (sizeof(regexp( ({s}), "m"))) {
741 gender = MALE;
742 } else {
743 gender = NEUTER;
744 }
745 return gender;
746}
747private string convMatDesc(string s) {
748 if (sizeof(regexp( ({s}), "- nicht vorhanden -"))) {
749 s = 0;
750 } else {
751 // Mehrzeilige Beschreibungen zu einer Zeile zusammenfassen
752 s = implode(explode(s, "\n"), " ");
753 }
754 return s;
755}
756private void addRecocLine(string s, mixed* r) {
757 // Die weitere Bewertung der Schwierigkeit kann erst vorgenommen werden,
758 // wenn alle Materialien bekannt sind und passiert spaeter. Zuerst werden
759 // nur die Elemente des Arrays konvertiert und eingetragen
760 string mat;
761 int val;
762 if (sscanf(s, "%s:%d", mat, val)) {
763 r += ({mat,val});
764 } else if (sscanf(s, "%d", val)) {
765 r += ({val});
766 } else {
767 r += ({s});
768 }
769}
770private mixed convMatRec(string s) {
771 mixed difficulties;
772 if (sizeof(regexp( ({s}), "- keine Einschraenkung -"))) {
773 difficulties = 0;
774 } else {
775 difficulties = ({});
776 // Jede Zeile enthaelt eine Bedingung
777 map(explode(s, "\n"), #'addRecocLine, &difficulties);
778 }
779 return difficulties;
780}
781private void addGroupLine(string s, mapping g) {
782 // Die weitere Bewertung der Zugehoerigkeit passiert spaeter.
783 string grp;
784 int val;
785 if (sscanf(s, "%s:%d", grp, val)) {
786 g += ([grp:val]);
787 } else {
788 g += ([grp:100]);
789 }
790}
791private mapping convMatGroups(string s) {
792 mapping groups;
793 if (!sizeof(regexp( ({s}), "- keine -"))) {
794 groups = ([]);
795 // Jede Zeile enthaelt eine Bedingung
796 map(explode(s, "\n"), #'addGroupLine, groups);
797 }
798 return groups;
799}
800private mapping convMaterialDesc(string id, mapping desc) {
801 /* Struktur Materialmapping:
802 P_GENDER,
803 P_NAME:({name_nom, name_gen, name_dativ, name_akkusativ}),
804 (P_RECOC:({mat1,faehigkeit1,mat2,faehigkeit2,...}),)
805 (P_DEFSTR: bei bedarf),
806 P_DESCRIPTION,
807 (grupp1:anteil1,
808 gruppe2:anteil2,
809 ...)
810 */
811 mapping m;
Arathornb3051452021-05-13 21:13:03 +0200812 mixed val;
MG Mud User88f12472016-06-24 23:31:02 +0200813 m = ([]);
814 // Der string fuer das #define zuerst:
815 val = convMatId(desc["Materialid"]);
816 if (mappingp(val)) {
817 if (val[P_ID] != id)
818 LOG_WARN(sprintf("Unstimmigkeit Materialid bei '%s':%O\n", id, val[P_ID]));
819 if (member(val, P_DEFSTR)) {
820 m += ([P_DEFSTR:val[P_DEFSTR]]);
821 } else {
822 // Wenn kein String fuers #define angegeben wurde, dann direkt ID verwenden
823 //m += ([P_DEFSTR:lowerstring(id)[4..]]);
824 }
825 }
826 // Die Namen
827 if (val = convMatNames(desc["Name"])) {
828 m += ([P_NAME:val]);
829 } else {
830 MDESC_WARN(id, "keine Namen");
831 m += ([P_NAME:({"", "", "", ""})]);
832 }
833 // Das Geschlecht, standard ist NEUTER
834 m += ([P_GENDER:convMatGender(desc["Geschlecht"]) ]);
835 // Die Beschreibung
836 val = convMatDesc(desc["Beschreibung"]);
837 if (sizeof(val)) {
838 m += ([P_DESCRIPTION:val]);
839 } else {
840 MDESC_WARN(id, "keine Beschreibung");
841 }
842 // Die Erkennbarkeit
843 val = convMatRec(desc["Erkennbarkeit"]);
844 if (sizeof(val)) {
845 m += ([P_RECOC:val]);
846 }
847 // und zum Schluss die Gruppenzugehoerigkeit
848 val = convMatGroups(desc["Gruppenzugehoerigkeit"]);
849 if (mappingp(val) && sizeof(val)) {
850 m += ([P_MG_FRACTIONS:val]);
851 }
852 return m;
853}
854private varargs mixed readMaterialDesc(string id) {
855 mixed m;
856 string fn;
857 fn = MAT_DIR+"/materials/"+id;
858 if (file_size(fn) > 0) {
859 mapping parts;
MG Mud User88f12472016-06-24 23:31:02 +0200860 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) {
Arathornb3051452021-05-13 21:13:03 +0200894 int start;
MG Mud User88f12472016-06-24 23:31:02 +0200895 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}