blob: fb8e3d1d496e17127a67023185871122fefe9c25 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// thing/description.c -- description handling for standard objects
4//
5// $Id: description.c 9561 2016-05-25 19:33:22Z Zesstra $
6
7#pragma strict_types
8#pragma save_types
9#pragma range_check
10#pragma no_clone
11#pragma pedantic
12
13#include <tls.h>
14#include <thing/description.h>
15#include <thing/material.h>
16#include <thing/lighttypes.h>
17#include <exploration.h> // wegen EPMASTER
18#include <class.h>
19
20#define NEED_PROTOTYPES
21#include <thing/properties.h>
22#include <thing/language.h>
23
24#undef NEED_PROTOTYPES
25#include <properties.h>
26
27// Variable um den FP abzuspeichern
28private nosave mixed *explore;
29
30// Prototypen
31public string short();
32public varargs string long(int mode);
33
34// #####################
35//######################## System-Funktionen ############################
36// #####################
37
38// Objekt erzeugen
39protected void create()
40{
41 string poid, tpid;
42 object tp;
43
44 SetProp( P_NAME, "Ding" );
45 SetProp( P_SHORT, "Nichts besonderes" );
46 SetProp( P_LONG, 0 );
47
48 Set( P_ADJECTIVES, ({}) );
49 Set( P_NAME_ADJ, ({}) );
50 Set( P_IDS, ({}) );
51 Set( P_CLASS, ({}) );
52
53 Set( P_READ_DETAILS, ([]), F_VALUE);
54 Set( P_READ_DETAILS, SECURED|NOSETMETHOD, F_MODE_AS);
55
56 Set( P_DETAILS, ([]), F_VALUE);
57 Set( P_DETAILS, SECURED|NOSETMETHOD, F_MODE_AS );
58
59 Set( P_SMELLS, ([]), F_VALUE);
60 Set( P_SMELLS, SECURED|NOSETMETHOD, F_MODE_AS );
61
62 Set( P_SOUNDS, ([]), F_VALUE);
63 Set( P_SOUNDS, SECURED|NOSETMETHOD, F_MODE_AS );
64
65 Set( P_TOUCH_DETAILS, ([]), F_VALUE);
66 Set( P_TOUCH_DETAILS, SECURED|NOSETMETHOD, F_MODE_AS );
67
68 // Aenderungen an dieser Prop sind tabu.
69 Set( P_CLONE_TIME, NOSETMETHOD|SECURED, F_MODE_AS );
70
Zesstrad3d45102018-02-13 20:06:11 +010071 // Id des Cloners und des Besitzers kommen nach P_CLONER
72 if (objectp( tp=this_interactive()||this_player() ))
MG Mud User88f12472016-06-24 23:31:02 +020073 {
Zesstrad3d45102018-02-13 20:06:11 +010074 tpid=geteuid(tp);
75 if (!(tpid=geteuid(tp))) tpid=getuid(tp);
MG Mud User88f12472016-06-24 23:31:02 +020076 }
77 else
Zesstrad3d45102018-02-13 20:06:11 +010078 tpid="UNKNOWN";
79
80 if (previous_object())
MG Mud User88f12472016-06-24 23:31:02 +020081 {
Zesstrad3d45102018-02-13 20:06:11 +010082 if (!(poid = geteuid(previous_object())))
83 poid = getuid(previous_object());
Zesstra789b1d82018-02-12 16:22:22 +010084 }
Zesstrad3d45102018-02-13 20:06:11 +010085 else
86 poid="UNKNOWN";
87
88 Set( P_CLONER, (poid != tpid ? poid+":"+tpid: tpid) );
89 Set( P_CLONER, NOSETMETHOD|SECURED, F_MODE_AS );
MG Mud User88f12472016-06-24 23:31:02 +020090
91 // Gibt es FPs ?
92 explore = (mixed *)EPMASTER->QueryExplore();
93
94 return;
95}
96
97protected void create_super() {
98 set_next_reset(-1);
99}
100
101// ##################
102//######################### Forscherpunkte ##############################
103// ##################
104
105// FP vergeben
106static void GiveEP( int type, string key )
107{
108 //Abbruch, wenn vergebendes Objekt schon zerstoert ist. ACHTUNG: Auch
109 //diese Abfrage wuerde kein FP vergeben werden, wenn sich das Objekt im
110 //vergebenden Kommando zerstoert, da der Driver call_other() von zerstoerten
111 //Objekten ignoriert!
112 if (!objectp(this_object())) return;
113 if (this_player()) this_player()->countCmds( type, key );
114
115 if (explore&&!extern_call()&&
116 (explore[0] == type) && (member(explore[1], key) >= 0) )
117 EPMASTER->GiveExplorationPoint(key);
118 return;
119}
120
121// Manche Objekte koennen mit rename_object einen neuen Filenamen bekommen.
122// Danach sollte der EPMASTER neu nach den Details befragt werden.
Zesstra0265bd82018-11-28 20:42:24 +0100123visible void __reload_explore()
MG Mud User88f12472016-06-24 23:31:02 +0200124{
125 explore = (mixed *)EPMASTER->QueryExplore();
126 return;
127}
128
129// #################
130//########################## ID-Management ##############################
131// #################
132
133// Gibt eine ID zurueck, die den Ladenamen, die aktuelle Kurzbeschreibung und
134// die aktuelle Langbeschreibung beruecksichtigt. Diese ID ist ein Hashwert.
135public string description_id() {
136 return hash(TLS_HASH_MD5, load_name() + short() + long());
137}
138
139/* Ids muessen uebergeben werden, da unit machmal mit plural-Ids, */
140/* also anderen als den normalen arbeiten muss. */
Zesstra0265bd82018-11-28 20:42:24 +0100141visible int match_item( string str, string *ids )
MG Mud User88f12472016-06-24 23:31:02 +0200142{
143 string *obj,*ads;
144 int len, i;
145
146 // Parameter falsch? Passt nicht ...
147 if(!str) return 0;
148 if(!pointerp(ids)) return 0;
149 if(!sizeof(ids)) return 0;
150
151 // Ist schon so dabei? Na Klasse :-)
152 if(member(ids,str)>-1) return 1;
153
154 // Keine Adjektive vorhanden ... passt nicht.
155 if (!(ads=QueryProp(P_ADJECTIVES))) return 0;
156 if (!sizeof(ads)) return 0;
157
158 // Nur ein Wort? Dann passt es nicht
159 obj=explode(str," ");
160 if (!(len=sizeof(obj)-1)) return 0;
161
162 // Adjektive stehen am Anfang. Sobald es nicht mehr passt,
163 // muss es das Objektiv sein.
164 while(i<len&&member(ads,obj[i])>-1) i++;
165
166 return (member(ids,implode(obj[i..len]," "))>-1);
167}
168
169// Wird vom Gamedriver aufgerufen (present)
170// Hat dieser Gegenstand die ID str?
171// lvl wird ignoriert
Zesstra0265bd82018-11-28 20:42:24 +0100172public varargs int id( string str, int lvl )
MG Mud User88f12472016-06-24 23:31:02 +0200173{
174 string str2, tmp;
175 int count;
176 string|string* ids;
177
178 // Kein Argument? Dann passt es nicht ...
179 if (!stringp(str)) return 0;
180
181 // Keine IDs? Auch nicht gut ...
182 if (!pointerp(ids=QueryProp(P_IDS))) return 0;
183 if (!sizeof(ids)) return 0;
184
185 ids += ({ ("\n" + object_name()),
186 ("\n" + explode(object_name(),"#")[0]) });
187
188 // Id passt? Alles klar :-)
189 if (match_item( str, ids )) return 1;
190
191 // Die id hat eine Zahl drin. Wenn Zahl die Rohid passt,
192 // dann gucken, ob man selber das nte Element ist.
193 if (sscanf( str, "%s %d%s", str2, count, tmp)<2) return 0;
194 if (count<1) return 0;
195 if (sizeof(tmp)) return 0;
196 if (!match_item( str2, ids )) return 0;
197 if (!environment()) return 0;
198 return present(str2,count,environment())==this_object();
199}
200
201// Gleich eine ganze Liste von ids testen
Zesstra0265bd82018-11-28 20:42:24 +0100202public int match_ids(string *list)
MG Mud User88f12472016-06-24 23:31:02 +0200203{
204 string *ids;
205
206 // Ungueltige Parameter? Weg hier ...
207 if (!pointerp(list)) return 0;
208 if (!pointerp(ids=QueryProp(P_IDS))) return 0;
209
210 ids += ({ ("\n" + object_name()),
211 ("\n" + explode(object_name(),"#")[0]) });
212
213 return sizeof( list & ids );
214}
215
216// ID hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100217public void AddId( string|string* str )
MG Mud User88f12472016-06-24 23:31:02 +0200218{
219 if (stringp(str)) str = ({ str });
220 if (pointerp(str))
221 // Doppelte eliminieren
222 Set( P_IDS, Query(P_IDS, F_VALUE)-str+str, F_VALUE);
223 return;
224}
225
226// ID entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100227public void RemoveId(string|string* str)
MG Mud User88f12472016-06-24 23:31:02 +0200228{
229 if (stringp(str)) str = ({ str });
230 if (pointerp(str))
231 Set(P_IDS,Query(P_IDS, F_VALUE)-str, F_VALUE);
232 return;
233}
234
235// Alle Ids auf einmal setzen
236static string* _set_ids( string* ids )
237{
238 Set( P_IDS,({}));
239 AddId(ids);
240 return Query(P_IDS, F_VALUE);
241}
242
243// Adjektiv hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100244public void AddAdjective(string|string* str)
MG Mud User88f12472016-06-24 23:31:02 +0200245{
246 if (stringp(str)) str = ({ str });
247 if (pointerp(str))
248 // Doppelte eliminieren
249 Set( P_ADJECTIVES, Query(P_ADJECTIVES, F_VALUE)-str+str, F_VALUE );
250 return;
251}
252
253// Adjektiv entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100254public void RemoveAdjective(string|string* str)
MG Mud User88f12472016-06-24 23:31:02 +0200255{
256 if (stringp(str)) str = ({ str });
257 if (pointerp(str))
258 Set( P_ADJECTIVES, Query(P_ADJECTIVES, F_VALUE) - str, F_VALUE );
259 return;
260}
261
262// Alle Adjektive auf einmal setzen
263static string* _set_adjectives(string* adjectives)
264{
265 Set( P_ADJECTIVES,({}), F_VALUE);
266 AddAdjective(adjectives);
267 return Query(P_ADJECTIVES, F_VALUE);
268}
269
270
271// ################
272//########################## Namensgebung ###############################
273// ################
274
275// Im Fall von mehreren Adjektiven muessen diese mit komma
276// zusamengebaut werden, dazu muss ich das leerzeichen aber erstmal
277// abschneiden und so weiter ...
Bugfixfd83c042017-02-18 11:45:35 +0100278private string depointer_adj( <string|string*>* adj, int casus, int demon ) {
MG Mud User88f12472016-06-24 23:31:02 +0200279 string msg;
280 int start;
281 string res,a;
282 adj = map( adj, #'DeclAdj, casus, demon );
283 start = 1;
284 res = "";
285 foreach( a: adj ) {
286 res += (start ? "" : ", ") + a[0..<2];
287 start = 0;
288 }
289 return res + " ";
290}
291
292// Wie lautet der Name des Objekts?
Zesstra0265bd82018-11-28 20:42:24 +0100293public varargs string name(int casus,int demon)
MG Mud User88f12472016-06-24 23:31:02 +0200294{
295 mixed sh, adj;
296 int art, plural;
297
298 art = QueryProp(P_ARTICLE);
299
300 // RAW: direkt zurueckgeben ohne Verarbeitung
301 if (casus == RAW )
302 {
303 if(pointerp(QueryProp(P_NAME)))
304 return QueryProp(P_NAME)[WER];
305 return QueryProp(P_NAME);
306 }
307
308 // Unsichtbar: Etwas
309 if (QueryProp(P_INVIS))
310 return ({ "etwas", "von etwas", "etwas", "etwas" })[casus];
311
312 // Kein Name? Schade ...
313 if (!(sh=QueryProp(P_NAME)) ||
314 (stringp(sh) && !sizeof(sh))) return 0;
315
316 // P_NAME pruefen.
317 if (pointerp(sh) && sizeof(sh) != 4)
318 raise_error(sprintf("Ungueltige Arraygroesse in P_NAME: %d\n",
319 sizeof(sh)));
320
321 // Plural .. Namen verwursten
322 if (plural = QueryProp(P_PLURAL))
323 {
324 // Selber Artikel suchen ist nicht ...
325 if (demon==2||!art) demon = 0;
326
327 // falls P_NAME ein Array mit Faellen enthaelt, den richtigen
328 // extrahieren...
329 if (pointerp(sh)) {
330 sh = sh[casus];
331 }
332 else {
333 // sonst versuchen, zu deklinieren.
334 int last = sh[<1];
335 if (casus == WEM&&last!='s'&&last!='n') sh = sh + "n";
336 }
337
338 // Sind Adjektive vorhanden?
339 if ( pointerp(adj = QueryProp(P_NAME_ADJ)) && sizeof(adj))
340 adj = depointer_adj(adj,casus,demon);
341 if (!stringp(adj)) adj = "";
342
343 return sprintf("%s%s%s%s",QueryArticle(casus,demon,0),adj,
344 (plural < 2 ? "":(plural < 8 ?
345 ({ "zwei ", "drei ", "vier ", "fuenf ", "sechs ",
346 "sieben " })[plural-2] : to_string(plural)+" ")),sh);
347 }
348
349 // Name ist Pointer: Einfach den richtigen auswaehlen
350 if (pointerp(sh))
351 sh = sh[casus];
352
353 // Ansonsten doch wieder verwursten ...
354 else if (stringp(sh))
355 {
356 int last = sh[<1];
357
358 switch(casus)
359 {
360 case WEM:
361 case WEN:
362 if ( art && last=='e'&&QueryProp(P_GENDER) == MALE)
363 sh = (string)sh + "n";
364 break;
365
366 case WESSEN:
367 if( !art )
368 {
369 switch(last)
370 {
371 case 'x':
372 case 's':
373 case 'z':
374 sh = (string)sh + "'";
375 break;
376
377 default:
378 sh = (string)sh + "s";
379 }
380 }
381 else
382 {
383 switch(last)
384 {
385 default:
386 if (QueryProp(P_GENDER)!=FEMALE)
387 sh=(string)sh+"s";
388 break;
389 case 'e':
390 if (QueryProp(P_GENDER)==MALE)
391 sh=(string)sh+"n";
392 case 'x':
393 case 's':
394 case 'z':
395 break;
396 } /* switch (last) */
397 } /* if( !art ) else */
398 } /* switch( casus ) */
399 } /* pointerp(sh) */
400
401 // RAW? Dann mal zurueck
402 if (demon == RAW) return (string)sh;
403
404 // Selber Artikel suchen ...
405 if (demon==2)
406 {
407 if (art)
408 demon = SuggestArticle();
409 else
410 demon=0; // Kein Artikel: egal (SuggestArticle ist zeitaufwendig)
411 }
412
413 if (pointerp(adj = QueryProp(P_NAME_ADJ)) && sizeof(adj))
414 adj = depointer_adj(adj,casus,demon);
415
416 if (!stringp(adj)) adj = "";
417
418 return QueryArticle( casus, demon )+adj+sh;
419}
420
421// Grossgeschriebenen Namen zurueckgeben
Zesstra0265bd82018-11-28 20:42:24 +0100422public varargs string Name( int casus, int demon )
MG Mud User88f12472016-06-24 23:31:02 +0200423{
424 return capitalize(name( casus, demon )||"");
425}
426
427// Langbeschreibung anzeigen
428public varargs string long(int mode)
429{
430 return process_string( QueryProp(P_LONG) );
431}
432
433// Kurzbeschreibung anzeigen, falls nicht unsichtbar
434public string short()
435{
436 string sh;
437
438 // Unsichtbar? Dann gibts nichts zu sehen ...
439 if (QueryProp(P_INVIS)||!(sh=QueryProp(P_SHORT)))
440 return 0;
Bugfixd6cd2e52017-02-27 18:23:42 +0100441
442 sh=process_string(sh);
443
444 // Ist das letzte Zeichen kein Satzzeichen, einen Punkt anhaengen.
445 // Note: matchen mit regexp [[:punct:]]$ waere sauberer bzgl. non-ASCII.
446 int i=sh[<1];
447 if(i!='.' && i!='!' && i!='?')
448 return sh+".\n";
449
450 return sh+"\n";
MG Mud User88f12472016-06-24 23:31:02 +0200451}
452
453// Namens-Adjektive setzen
Bugfixdc6d7352016-11-14 13:14:31 +0100454static <string|string*>* _set_name_adj(string|<string|string*>* adjectives)
MG Mud User88f12472016-06-24 23:31:02 +0200455{
456 if (!adjectives)
457 adjectives=({});
458 // In Array umwandeln
459 else if ( !pointerp(adjectives))
460 adjectives = ({ to_string(adjectives) });
461 return Set( P_NAME_ADJ, adjectives );
462}
463
464// ############################
465//#################### Details, Gerueche, Laerm #########################
466// ############################
467
468// Low-level Funktion zum Ergaenzen von Details, wird von den div. Add...()
469// gerufen, die das richtige Mapping uebergeben.
470// Aendert das Mapping <details> direkt.
471private void _add_details(string|string* keys,
472 string|string*|mapping|closure descr,
473 mapping details )
474{
475 if (stringp(keys))
Arathorn444e9ff2016-09-03 15:11:41 +0200476 details[lower_case(keys)]=descr;
MG Mud User88f12472016-06-24 23:31:02 +0200477 else if (pointerp(keys))
478 {
479 foreach(string key : keys)
480 details[lower_case(key)]=descr;
481 }
482 else
483 raise_error("Wrong type to argument 1, expected string|string*.\n");
484}
485
486// Low-level Funktion zum Entfernen von Details, wird von den div. Remove...()
487// gerufen, die das richtige Mapping uebergeben.
488// Aendert das Mapping <details> direkt.
489private void _remove_details(string|string* keys, mapping details )
490{
491 if (stringp(keys))
492 details -= ([keys]);
493 else if (pointerp(keys))
494 details -= mkmapping(keys);
495 else
496 raise_error("Wrong type to argument 1, expected string|string*.\n");
497}
498
499// Detail(s) hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100500public void AddDetail(string|string* keys, string|string*|mapping|closure descr)
MG Mud User88f12472016-06-24 23:31:02 +0200501{
502 int i;
503 mapping details;
504
505 details = Query(P_DETAILS, F_VALUE);
506
507 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
508 return _add_details(keys, descr, details);
509}
510
511// Detail(s) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100512public varargs void RemoveDetail(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200513{
514 // Alle loeschen geht direkt ...
515 if (!keys )
516 Set(P_DETAILS, ([]), F_VALUE);
517 else
518 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
519 _remove_details(keys, Query(P_DETAILS, F_VALUE));
520}
521
522// SpecialDetail hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100523visible void AddSpecialDetail(string|string* keys, string functionname )
MG Mud User88f12472016-06-24 23:31:02 +0200524{
525 closure cl;
526
527 // Absichern! Sonst koennte jeder interne Funktionen aufrufen
528 if (extern_call() &&
529 (geteuid(previous_object()) != geteuid() || process_call()) &&
530 !(object_name(previous_object()) == "/obj/doormaster" &&
531 functionname == "special_detail_doors") )
532 raise_error( "Illegal use of AddSpecialDetail!\n" );
533
534 // Closure generieren
535 if ( !stringp(functionname)||
536 !(cl = symbol_function( functionname, this_object())) )
537 return;
538
539 // Detail hinzufuegen
540 AddDetail( keys, cl );
541 return;
542}
543
544// SpecialDetail(s) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100545visible void RemoveSpecialDetail(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200546{
547 // RemoveSpecialDetail(0) wuerde sonst ALLE Details (auch die
548 // 'normalen') loeschen
549 if (pointerp(keys)||stringp(keys))
550 RemoveDetail(keys);
551 return;
552}
553
554// Lesbares Detail einfuegen
Zesstra0265bd82018-11-28 20:42:24 +0100555public void AddReadDetail(string|string* keys,
MG Mud User88f12472016-06-24 23:31:02 +0200556 string|string*|mapping|closure descr )
557{
558 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
559 return _add_details(keys, descr, Query(P_READ_DETAILS, F_VALUE));
560}
561
562// Lesbare(s) Detail(s) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100563public varargs void RemoveReadDetail(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200564{
565 // Alle loeschen geht direkt ...
566 if (!keys )
567 Set(P_READ_DETAILS, ([]), F_VALUE);
568 else
569 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
570 _remove_details(keys, Query(P_READ_DETAILS, F_VALUE));
571}
572
573// Geraeusch(e) dazufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100574public void AddSounds(string|string* keys,
MG Mud User88f12472016-06-24 23:31:02 +0200575 string|string*|mapping|closure descr )
576{
577 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
578 return _add_details(keys, descr, Query(P_SOUNDS, F_VALUE));
579}
580
581// Geraeusch(e) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100582public varargs void RemoveSounds(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200583{
584 // Alle loeschen geht direkt ...
585 if (!keys )
586 Set(P_SOUNDS, ([]), F_VALUE);
587 else
588 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
589 _remove_details(keys, Query(P_SOUNDS, F_VALUE));
590}
591
592// Geru(e)ch(e) hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100593public void AddSmells(string|string* keys,
MG Mud User88f12472016-06-24 23:31:02 +0200594 string|string*|mapping|closure descr )
595{
596 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
597 return _add_details(keys, descr, Query(P_SMELLS, F_VALUE));
598}
599
600// Geru(e)ch(e) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100601public varargs void RemoveSmells(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200602{
603 // Alle loeschen geht direkt ...
604 if (!keys )
605 Set(P_SMELLS, ([]), F_VALUE);
606 else
607 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
608 _remove_details(keys, Query(P_SMELLS, F_VALUE));
609}
610
611// Tastbare(s) Detail(s) hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100612public void AddTouchDetail(string|string* keys,
MG Mud User88f12472016-06-24 23:31:02 +0200613 string|string*|mapping|closure descr )
614{
615 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
616 return _add_details(keys, descr, Query(P_TOUCH_DETAILS, F_VALUE));
617}
618
619// Tastbare(s) Detail(s) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100620public varargs void RemoveTouchDetails(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200621{
622 // Alle loeschen geht direkt ...
623 if (!keys )
624 Set(P_TOUCH_DETAILS, ([]), F_VALUE);
625 else
626 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
627 _remove_details(keys, Query(P_TOUCH_DETAILS, F_VALUE));
628}
629
630// Detailinfos fuer Detail key, Spieler hat die Rasse race
631// und benutzt seinen Sinn sense
Zesstra0265bd82018-11-28 20:42:24 +0100632public varargs string GetDetail(string key, string race, int sense)
MG Mud User88f12472016-06-24 23:31:02 +0200633{
634 string|string*|mapping|closure detail;
635
636 if (stringp(race)) race = lower_case(race);
637
638 switch(sense)
639 {
640 case SENSE_SMELL: detail=Query(P_SMELLS, F_VALUE)[key];
641 sense=EP_SMELL; break;
642 case SENSE_SOUND: detail=Query(P_SOUNDS, F_VALUE)[key];
643 sense=EP_SOUND; break;
644 case SENSE_TOUCH: detail=Query(P_TOUCH_DETAILS, F_VALUE)[key];
645 sense=EP_TOUCH; break;
646 case SENSE_READ: detail=Query(P_READ_DETAILS, F_VALUE)[key];
647 sense=EP_RDET;
648 break;
649
650 default: detail=Query(P_DETAILS, F_VALUE)[key];
651 sense=EP_DETAIL; break;
652 }
653
654 if (!stringp(detail))
655 {
656 if (closurep(detail))
657 detail = (string)funcall(detail,key);
658 else if (mappingp(detail))
659 detail = (string)(detail[race]||detail[0]);
660 else if (pointerp(detail))
661 detail = (string)(detail[random(sizeof(detail))]);
662 }
663
664 // FP vergeben (so vorhanden ;-) )
665 if (detail) GiveEP(sense,key);
666
667 return detail;
668}
669
670// TODO: OBSOLET (Libgrep notwendig)
671void read( string str ) {
672 raise_error("Diese Funktion existiert nicht mehr.\n");
673}
674
675
676// ######################
677//####################### Zugriffsfunktionen ############################
678// ######################
679
680// Dienen dazu, die direkte Manipulation der Props von aussen zu erschweren.
681
682// Filter, um Specialdetails zu eliminieren
683// erstellt ausserdem ne Kopie vom Mapping. (Wichtig!)
684// Wird vor allem benoetigt, um P_DETAILS in P_DETAILS und
685// P_SPECIAL_DETAILS zu treffen.
686private int _closures(string x, mapping details, int yes )
687{
688 return yes ? closurep(details[x]) : !closurep(details[x]);
689}
690
691static mapping _query_details()
692{
693 return filter_indices(Query(P_DETAILS, F_VALUE), #'_closures,
694 Query(P_DETAILS, F_VALUE),0);
695}
696
697static mapping _query_special_details()
698{
699 return filter_indices(Query(P_DETAILS, F_VALUE),#'_closures,
700 Query(P_DETAILS, F_VALUE),1);
701}
702
703static mapping _query_read_details() {
704 return deep_copy(Query(P_READ_DETAILS, F_VALUE));
705}
706
707static mapping _query_sound_details() {
708 return deep_copy(Query(P_SOUNDS, F_VALUE));
709}
710
711static mapping _query_smell_details() {
712 return deep_copy(Query(P_SMELLS, F_VALUE));
713}
714
715
716// ##########################
717//##################### Klassen-Mitgliedschaft ##########################
718// ##########################
719
720// Klasse hinzufuegen
721public void AddClass(string|string* str)
722{
723 if (stringp(str))
724 str = ({ str });
725 // Aliase aufloesen und implizite Klassen addieren.
726 str = (string*)CLASSDB->AddImplicitClasses(str);
727 // Summe mit alten Klassen bilden und Doppelte eliminieren
728 str = str + Query(P_CLASS, F_VALUE);
729 Set( P_CLASS, m_indices(mkmapping(str)), F_VALUE);
730
731 return;
732}
733
734// Klasse entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100735public void RemoveClass(string|string* str)
MG Mud User88f12472016-06-24 23:31:02 +0200736{
737 if (stringp(str))
738 str = ({ str });
739
740 // Aliase aufloesen und implizite Klassen addieren.
741 str = (string*)CLASSDB->AddImplicitClasses(str);
742
743 // Und alle - inklusive impliziter Klassen - entfernen
744 // TODO: Pruefen, ob dies die richtige Entscheidung ist.
745 Set( P_CLASS, Query(P_CLASS, F_VALUE)-str, F_VALUE);
746
747 return;
748}
749
750// Ist das Objekt Mitglied der Klasse str?
Zesstra0265bd82018-11-28 20:42:24 +0100751public int is_class_member(string|string* str)
MG Mud User88f12472016-06-24 23:31:02 +0200752{
753 // Keine Klasse, keine Mitgliedschaft ...
754 if (!str || str=="")
755 return 0;
756
757 // Es sollte schon ein Array sein
758 if (stringp(str))
759 str = ({ str });
760
761 // Klassen und Ids ins Array
762 string *classes=QueryProp(P_CLASS);
763 if (!pointerp(classes))
764 return 0;
765
766 // .. und testen
767 foreach(string class : str)
768 if (member(classes,class) > -1 ) return 1;
769
770 return 0;
771}
772
773// Klasse direkt setzen abfangen
774static string* _set_class(string* classes )
775{
776 Set( P_CLASS, ({}), F_VALUE );
777 AddClass(classes);
778 return QueryProp(P_CLASS);
779}
780
781// #####################
782//######################## Material-Handling ############################
783// #####################
784
785// Material setzen
786static mapping _set_material(mapping|string|string* mat )
787{
788 mapping mats = ([]);
789
790 if (mappingp(mat))
791 {
792 if( !sizeof(mat) || !widthof(mat) )
793 raise_error(sprintf("P_MATERIAL: expected mapping with at least one "
794 "key and one value, got %.50O\n",mat));
795 else
796 mats = mat;
797 }
798 else if (stringp(mat))
799 mats[mat]=100;
800 else
801 {
802 int sz = sizeof(mat);
803 // Kommt dann vor, wenn <mat> 0 oder ({}) ist.
804 if ( !sz )
805 raise_error(sprintf("P_MATERIAL: expected string or non-empty "
806 "mapping|string*, got %.50O.\n", mat));
807 mats = mkmapping(mat, allocate(sz, 100/sz));
808 }
809 return Set( P_MATERIAL, mats, F_VALUE );
810}
811
812// Woraus besteht das Objekt?
813static mapping _query_material()
814{
815 mixed res;
816
817 if ( !mappingp(res = Query(P_MATERIAL, F_VALUE)) )
818 return ([MAT_MISC:100]);
819
820 return res;
821}
822
823// Anteil von mat am Objekt?
Zesstra0265bd82018-11-28 20:42:24 +0100824public int QueryMaterial( string mat )
MG Mud User88f12472016-06-24 23:31:02 +0200825{
826 mapping mats;
827
828 if ( !mappingp(mats = QueryProp(P_MATERIAL)) )
829 return 0;
830
831 return mats[mat];
832}
833
834// Anteil der Gruppe am Objekt
Zesstra0265bd82018-11-28 20:42:24 +0100835public int QueryMaterialGroup( string matgroup )
MG Mud User88f12472016-06-24 23:31:02 +0200836{
837 return (int)call_other( MATERIALDB, "MaterialGroup",
838 QueryProp(P_MATERIAL), matgroup );
839}
840
841
Zesstra0265bd82018-11-28 20:42:24 +0100842public string MaterialList( int casus, mixed idinf )
MG Mud User88f12472016-06-24 23:31:02 +0200843{
844 return (string)call_other( MATERIALDB, "ConvMaterialList",
845 QueryProp(P_MATERIAL), casus, idinf );
846}
847
848static int _set_size(int sz) {
849//Groesse muss > 0 sein, alles andere ist unsinnig! (0 und neg. Groessen
850//haben keine phys. Relevanz und machen u.U. Probleme mit Objekten, die
851//Schaden in Abhaengigkeit der Groesse machen)
852 if (sz>0)
853 Set(P_SIZE,sz,F_VALUE);
854 return(Query(P_SIZE,F_VALUE));
855}
856
857// P_CLONE_TIME
858static int _query_clone_time() { return object_time(); }
859