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