blob: db238d27f235bff9dbb901f6a83193c5eed13865 [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 int start;
279 string res,a;
280 adj = map( adj, #'DeclAdj, casus, demon );
281 start = 1;
282 res = "";
283 foreach( a: adj ) {
284 res += (start ? "" : ", ") + a[0..<2];
285 start = 0;
286 }
287 return res + " ";
288}
289
290// Wie lautet der Name des Objekts?
Zesstra0265bd82018-11-28 20:42:24 +0100291public varargs string name(int casus,int demon)
MG Mud User88f12472016-06-24 23:31:02 +0200292{
293 mixed sh, adj;
294 int art, plural;
295
296 art = QueryProp(P_ARTICLE);
297
298 // RAW: direkt zurueckgeben ohne Verarbeitung
299 if (casus == RAW )
300 {
301 if(pointerp(QueryProp(P_NAME)))
302 return QueryProp(P_NAME)[WER];
303 return QueryProp(P_NAME);
304 }
305
306 // Unsichtbar: Etwas
307 if (QueryProp(P_INVIS))
308 return ({ "etwas", "von etwas", "etwas", "etwas" })[casus];
309
310 // Kein Name? Schade ...
311 if (!(sh=QueryProp(P_NAME)) ||
312 (stringp(sh) && !sizeof(sh))) return 0;
313
314 // P_NAME pruefen.
315 if (pointerp(sh) && sizeof(sh) != 4)
316 raise_error(sprintf("Ungueltige Arraygroesse in P_NAME: %d\n",
317 sizeof(sh)));
318
319 // Plural .. Namen verwursten
320 if (plural = QueryProp(P_PLURAL))
321 {
322 // Selber Artikel suchen ist nicht ...
323 if (demon==2||!art) demon = 0;
324
325 // falls P_NAME ein Array mit Faellen enthaelt, den richtigen
326 // extrahieren...
327 if (pointerp(sh)) {
328 sh = sh[casus];
329 }
330 else {
331 // sonst versuchen, zu deklinieren.
332 int last = sh[<1];
333 if (casus == WEM&&last!='s'&&last!='n') sh = sh + "n";
334 }
335
336 // Sind Adjektive vorhanden?
337 if ( pointerp(adj = QueryProp(P_NAME_ADJ)) && sizeof(adj))
338 adj = depointer_adj(adj,casus,demon);
339 if (!stringp(adj)) adj = "";
340
341 return sprintf("%s%s%s%s",QueryArticle(casus,demon,0),adj,
342 (plural < 2 ? "":(plural < 8 ?
343 ({ "zwei ", "drei ", "vier ", "fuenf ", "sechs ",
344 "sieben " })[plural-2] : to_string(plural)+" ")),sh);
345 }
346
347 // Name ist Pointer: Einfach den richtigen auswaehlen
348 if (pointerp(sh))
349 sh = sh[casus];
350
351 // Ansonsten doch wieder verwursten ...
352 else if (stringp(sh))
353 {
354 int last = sh[<1];
355
356 switch(casus)
357 {
358 case WEM:
359 case WEN:
360 if ( art && last=='e'&&QueryProp(P_GENDER) == MALE)
Vanion50652322020-03-10 21:13:25 +0100361 sh = sh + "n";
MG Mud User88f12472016-06-24 23:31:02 +0200362 break;
363
364 case WESSEN:
365 if( !art )
366 {
367 switch(last)
368 {
369 case 'x':
370 case 's':
371 case 'z':
Vanion50652322020-03-10 21:13:25 +0100372 sh = sh + "'";
MG Mud User88f12472016-06-24 23:31:02 +0200373 break;
374
375 default:
Vanion50652322020-03-10 21:13:25 +0100376 sh = sh + "s";
MG Mud User88f12472016-06-24 23:31:02 +0200377 }
378 }
379 else
380 {
381 switch(last)
382 {
383 default:
384 if (QueryProp(P_GENDER)!=FEMALE)
Vanion50652322020-03-10 21:13:25 +0100385 sh=sh+"s";
MG Mud User88f12472016-06-24 23:31:02 +0200386 break;
387 case 'e':
388 if (QueryProp(P_GENDER)==MALE)
Vanion50652322020-03-10 21:13:25 +0100389 sh=sh+"n";
MG Mud User88f12472016-06-24 23:31:02 +0200390 case 'x':
391 case 's':
392 case 'z':
393 break;
394 } /* switch (last) */
395 } /* if( !art ) else */
396 } /* switch( casus ) */
397 } /* pointerp(sh) */
398
399 // RAW? Dann mal zurueck
Vanion50652322020-03-10 21:13:25 +0100400 if (demon == RAW) return sh;
MG Mud User88f12472016-06-24 23:31:02 +0200401
402 // Selber Artikel suchen ...
403 if (demon==2)
404 {
405 if (art)
406 demon = SuggestArticle();
407 else
408 demon=0; // Kein Artikel: egal (SuggestArticle ist zeitaufwendig)
409 }
410
411 if (pointerp(adj = QueryProp(P_NAME_ADJ)) && sizeof(adj))
412 adj = depointer_adj(adj,casus,demon);
413
414 if (!stringp(adj)) adj = "";
415
416 return QueryArticle( casus, demon )+adj+sh;
417}
418
419// Grossgeschriebenen Namen zurueckgeben
Zesstra0265bd82018-11-28 20:42:24 +0100420public varargs string Name( int casus, int demon )
MG Mud User88f12472016-06-24 23:31:02 +0200421{
422 return capitalize(name( casus, demon )||"");
423}
424
425// Langbeschreibung anzeigen
426public varargs string long(int mode)
427{
428 return process_string( QueryProp(P_LONG) );
429}
430
431// Kurzbeschreibung anzeigen, falls nicht unsichtbar
432public string short()
433{
Zesstrada737162019-11-25 22:36:14 +0100434 string|closure sh;
MG Mud User88f12472016-06-24 23:31:02 +0200435
436 // Unsichtbar? Dann gibts nichts zu sehen ...
437 if (QueryProp(P_INVIS)||!(sh=QueryProp(P_SHORT)))
438 return 0;
Bugfixd6cd2e52017-02-27 18:23:42 +0100439
440 sh=process_string(sh);
441
442 // Ist das letzte Zeichen kein Satzzeichen, einen Punkt anhaengen.
443 // Note: matchen mit regexp [[:punct:]]$ waere sauberer bzgl. non-ASCII.
444 int i=sh[<1];
445 if(i!='.' && i!='!' && i!='?')
446 return sh+".\n";
447
448 return sh+"\n";
MG Mud User88f12472016-06-24 23:31:02 +0200449}
450
451// Namens-Adjektive setzen
Bugfixdc6d7352016-11-14 13:14:31 +0100452static <string|string*>* _set_name_adj(string|<string|string*>* adjectives)
MG Mud User88f12472016-06-24 23:31:02 +0200453{
454 if (!adjectives)
455 adjectives=({});
456 // In Array umwandeln
457 else if ( !pointerp(adjectives))
458 adjectives = ({ to_string(adjectives) });
459 return Set( P_NAME_ADJ, adjectives );
460}
461
462// ############################
463//#################### Details, Gerueche, Laerm #########################
464// ############################
465
466// Low-level Funktion zum Ergaenzen von Details, wird von den div. Add...()
467// gerufen, die das richtige Mapping uebergeben.
468// Aendert das Mapping <details> direkt.
469private void _add_details(string|string* keys,
470 string|string*|mapping|closure descr,
471 mapping details )
472{
473 if (stringp(keys))
Arathorn444e9ff2016-09-03 15:11:41 +0200474 details[lower_case(keys)]=descr;
MG Mud User88f12472016-06-24 23:31:02 +0200475 else if (pointerp(keys))
476 {
477 foreach(string key : keys)
478 details[lower_case(key)]=descr;
479 }
480 else
481 raise_error("Wrong type to argument 1, expected string|string*.\n");
482}
483
484// Low-level Funktion zum Entfernen von Details, wird von den div. Remove...()
485// gerufen, die das richtige Mapping uebergeben.
486// Aendert das Mapping <details> direkt.
487private void _remove_details(string|string* keys, mapping details )
488{
489 if (stringp(keys))
490 details -= ([keys]);
491 else if (pointerp(keys))
492 details -= mkmapping(keys);
493 else
494 raise_error("Wrong type to argument 1, expected string|string*.\n");
495}
496
497// Detail(s) hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100498public void AddDetail(string|string* keys, string|string*|mapping|closure descr)
MG Mud User88f12472016-06-24 23:31:02 +0200499{
MG Mud User88f12472016-06-24 23:31:02 +0200500 mapping details;
501
502 details = Query(P_DETAILS, F_VALUE);
503
504 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
505 return _add_details(keys, descr, details);
506}
507
508// Detail(s) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100509public varargs void RemoveDetail(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200510{
511 // Alle loeschen geht direkt ...
512 if (!keys )
513 Set(P_DETAILS, ([]), F_VALUE);
514 else
515 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
516 _remove_details(keys, Query(P_DETAILS, F_VALUE));
517}
518
519// SpecialDetail hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100520visible void AddSpecialDetail(string|string* keys, string functionname )
MG Mud User88f12472016-06-24 23:31:02 +0200521{
522 closure cl;
523
524 // Absichern! Sonst koennte jeder interne Funktionen aufrufen
525 if (extern_call() &&
526 (geteuid(previous_object()) != geteuid() || process_call()) &&
527 !(object_name(previous_object()) == "/obj/doormaster" &&
528 functionname == "special_detail_doors") )
529 raise_error( "Illegal use of AddSpecialDetail!\n" );
530
531 // Closure generieren
532 if ( !stringp(functionname)||
533 !(cl = symbol_function( functionname, this_object())) )
534 return;
535
536 // Detail hinzufuegen
537 AddDetail( keys, cl );
538 return;
539}
540
541// SpecialDetail(s) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100542visible void RemoveSpecialDetail(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200543{
544 // RemoveSpecialDetail(0) wuerde sonst ALLE Details (auch die
545 // 'normalen') loeschen
546 if (pointerp(keys)||stringp(keys))
547 RemoveDetail(keys);
548 return;
549}
550
551// Lesbares Detail einfuegen
Zesstra0265bd82018-11-28 20:42:24 +0100552public void AddReadDetail(string|string* keys,
MG Mud User88f12472016-06-24 23:31:02 +0200553 string|string*|mapping|closure descr )
554{
555 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
556 return _add_details(keys, descr, Query(P_READ_DETAILS, F_VALUE));
557}
558
559// Lesbare(s) Detail(s) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100560public varargs void RemoveReadDetail(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200561{
562 // Alle loeschen geht direkt ...
563 if (!keys )
564 Set(P_READ_DETAILS, ([]), F_VALUE);
565 else
566 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
567 _remove_details(keys, Query(P_READ_DETAILS, F_VALUE));
568}
569
570// Geraeusch(e) dazufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100571public void AddSounds(string|string* keys,
MG Mud User88f12472016-06-24 23:31:02 +0200572 string|string*|mapping|closure descr )
573{
574 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
575 return _add_details(keys, descr, Query(P_SOUNDS, F_VALUE));
576}
577
578// Geraeusch(e) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100579public varargs void RemoveSounds(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200580{
581 // Alle loeschen geht direkt ...
582 if (!keys )
583 Set(P_SOUNDS, ([]), F_VALUE);
584 else
585 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
586 _remove_details(keys, Query(P_SOUNDS, F_VALUE));
587}
588
589// Geru(e)ch(e) hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100590public void AddSmells(string|string* keys,
MG Mud User88f12472016-06-24 23:31:02 +0200591 string|string*|mapping|closure descr )
592{
593 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
594 return _add_details(keys, descr, Query(P_SMELLS, F_VALUE));
595}
596
597// Geru(e)ch(e) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100598public varargs void RemoveSmells(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200599{
600 // Alle loeschen geht direkt ...
601 if (!keys )
602 Set(P_SMELLS, ([]), F_VALUE);
603 else
604 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
605 _remove_details(keys, Query(P_SMELLS, F_VALUE));
606}
607
608// Tastbare(s) Detail(s) hinzufuegen
Zesstra0265bd82018-11-28 20:42:24 +0100609public void AddTouchDetail(string|string* keys,
MG Mud User88f12472016-06-24 23:31:02 +0200610 string|string*|mapping|closure descr )
611{
612 // _add_details() aendern das Mapping direkt, Set etc. nicht noetig.
613 return _add_details(keys, descr, Query(P_TOUCH_DETAILS, F_VALUE));
614}
615
616// Tastbare(s) Detail(s) entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100617public varargs void RemoveTouchDetails(string|string* keys )
MG Mud User88f12472016-06-24 23:31:02 +0200618{
619 // Alle loeschen geht direkt ...
620 if (!keys )
621 Set(P_TOUCH_DETAILS, ([]), F_VALUE);
622 else
623 // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig.
624 _remove_details(keys, Query(P_TOUCH_DETAILS, F_VALUE));
625}
626
627// Detailinfos fuer Detail key, Spieler hat die Rasse race
628// und benutzt seinen Sinn sense
Zesstra0265bd82018-11-28 20:42:24 +0100629public varargs string GetDetail(string key, string race, int sense)
MG Mud User88f12472016-06-24 23:31:02 +0200630{
631 string|string*|mapping|closure detail;
632
633 if (stringp(race)) race = lower_case(race);
634
635 switch(sense)
636 {
637 case SENSE_SMELL: detail=Query(P_SMELLS, F_VALUE)[key];
638 sense=EP_SMELL; break;
639 case SENSE_SOUND: detail=Query(P_SOUNDS, F_VALUE)[key];
640 sense=EP_SOUND; break;
641 case SENSE_TOUCH: detail=Query(P_TOUCH_DETAILS, F_VALUE)[key];
642 sense=EP_TOUCH; break;
643 case SENSE_READ: detail=Query(P_READ_DETAILS, F_VALUE)[key];
644 sense=EP_RDET;
645 break;
646
647 default: detail=Query(P_DETAILS, F_VALUE)[key];
648 sense=EP_DETAIL; break;
649 }
650
651 if (!stringp(detail))
652 {
653 if (closurep(detail))
Vanion50652322020-03-10 21:13:25 +0100654 detail = ({string})funcall(detail,key);
MG Mud User88f12472016-06-24 23:31:02 +0200655 else if (mappingp(detail))
Vanion50652322020-03-10 21:13:25 +0100656 detail = detail[race] || detail[0];
MG Mud User88f12472016-06-24 23:31:02 +0200657 else if (pointerp(detail))
Vanion50652322020-03-10 21:13:25 +0100658 detail = detail[random(sizeof(detail))];
MG Mud User88f12472016-06-24 23:31:02 +0200659 }
660
661 // FP vergeben (so vorhanden ;-) )
662 if (detail) GiveEP(sense,key);
663
664 return detail;
665}
666
667// TODO: OBSOLET (Libgrep notwendig)
668void read( string str ) {
669 raise_error("Diese Funktion existiert nicht mehr.\n");
670}
671
672
673// ######################
674//####################### Zugriffsfunktionen ############################
675// ######################
676
677// Dienen dazu, die direkte Manipulation der Props von aussen zu erschweren.
678
679// Filter, um Specialdetails zu eliminieren
680// erstellt ausserdem ne Kopie vom Mapping. (Wichtig!)
681// Wird vor allem benoetigt, um P_DETAILS in P_DETAILS und
682// P_SPECIAL_DETAILS zu treffen.
683private int _closures(string x, mapping details, int yes )
684{
685 return yes ? closurep(details[x]) : !closurep(details[x]);
686}
687
688static mapping _query_details()
689{
690 return filter_indices(Query(P_DETAILS, F_VALUE), #'_closures,
691 Query(P_DETAILS, F_VALUE),0);
692}
693
694static mapping _query_special_details()
695{
696 return filter_indices(Query(P_DETAILS, F_VALUE),#'_closures,
697 Query(P_DETAILS, F_VALUE),1);
698}
699
700static mapping _query_read_details() {
701 return deep_copy(Query(P_READ_DETAILS, F_VALUE));
702}
703
704static mapping _query_sound_details() {
705 return deep_copy(Query(P_SOUNDS, F_VALUE));
706}
707
708static mapping _query_smell_details() {
709 return deep_copy(Query(P_SMELLS, F_VALUE));
710}
711
712
713// ##########################
714//##################### Klassen-Mitgliedschaft ##########################
715// ##########################
716
717// Klasse hinzufuegen
718public void AddClass(string|string* str)
719{
720 if (stringp(str))
721 str = ({ str });
722 // Aliase aufloesen und implizite Klassen addieren.
Vanion50652322020-03-10 21:13:25 +0100723 str = ({string*})CLASSDB->AddImplicitClasses(str);
MG Mud User88f12472016-06-24 23:31:02 +0200724 // Summe mit alten Klassen bilden und Doppelte eliminieren
725 str = str + Query(P_CLASS, F_VALUE);
726 Set( P_CLASS, m_indices(mkmapping(str)), F_VALUE);
727
728 return;
729}
730
731// Klasse entfernen
Zesstra0265bd82018-11-28 20:42:24 +0100732public void RemoveClass(string|string* str)
MG Mud User88f12472016-06-24 23:31:02 +0200733{
734 if (stringp(str))
735 str = ({ str });
736
737 // Aliase aufloesen und implizite Klassen addieren.
Vanion50652322020-03-10 21:13:25 +0100738 str = ({string*})CLASSDB->AddImplicitClasses(str);
MG Mud User88f12472016-06-24 23:31:02 +0200739
740 // Und alle - inklusive impliziter Klassen - entfernen
741 // TODO: Pruefen, ob dies die richtige Entscheidung ist.
742 Set( P_CLASS, Query(P_CLASS, F_VALUE)-str, F_VALUE);
743
744 return;
745}
746
747// Ist das Objekt Mitglied der Klasse str?
Zesstra0265bd82018-11-28 20:42:24 +0100748public int is_class_member(string|string* str)
MG Mud User88f12472016-06-24 23:31:02 +0200749{
750 // Keine Klasse, keine Mitgliedschaft ...
751 if (!str || str=="")
752 return 0;
753
754 // Es sollte schon ein Array sein
755 if (stringp(str))
756 str = ({ str });
757
758 // Klassen und Ids ins Array
759 string *classes=QueryProp(P_CLASS);
760 if (!pointerp(classes))
761 return 0;
762
763 // .. und testen
764 foreach(string class : str)
765 if (member(classes,class) > -1 ) return 1;
766
767 return 0;
768}
769
770// Klasse direkt setzen abfangen
771static string* _set_class(string* classes )
772{
773 Set( P_CLASS, ({}), F_VALUE );
774 AddClass(classes);
775 return QueryProp(P_CLASS);
776}
777
778// #####################
779//######################## Material-Handling ############################
780// #####################
781
782// Material setzen
783static mapping _set_material(mapping|string|string* mat )
784{
785 mapping mats = ([]);
786
787 if (mappingp(mat))
788 {
789 if( !sizeof(mat) || !widthof(mat) )
790 raise_error(sprintf("P_MATERIAL: expected mapping with at least one "
791 "key and one value, got %.50O\n",mat));
792 else
793 mats = mat;
794 }
795 else if (stringp(mat))
796 mats[mat]=100;
797 else
798 {
799 int sz = sizeof(mat);
800 // Kommt dann vor, wenn <mat> 0 oder ({}) ist.
801 if ( !sz )
802 raise_error(sprintf("P_MATERIAL: expected string or non-empty "
803 "mapping|string*, got %.50O.\n", mat));
804 mats = mkmapping(mat, allocate(sz, 100/sz));
805 }
806 return Set( P_MATERIAL, mats, F_VALUE );
807}
808
809// Woraus besteht das Objekt?
810static mapping _query_material()
811{
812 mixed res;
813
814 if ( !mappingp(res = Query(P_MATERIAL, F_VALUE)) )
815 return ([MAT_MISC:100]);
816
817 return res;
818}
819
820// Anteil von mat am Objekt?
Zesstra0265bd82018-11-28 20:42:24 +0100821public int QueryMaterial( string mat )
MG Mud User88f12472016-06-24 23:31:02 +0200822{
823 mapping mats;
824
825 if ( !mappingp(mats = QueryProp(P_MATERIAL)) )
826 return 0;
827
828 return mats[mat];
829}
830
831// Anteil der Gruppe am Objekt
Zesstra0265bd82018-11-28 20:42:24 +0100832public int QueryMaterialGroup( string matgroup )
MG Mud User88f12472016-06-24 23:31:02 +0200833{
Vanion50652322020-03-10 21:13:25 +0100834 return ({int})call_other( MATERIALDB, "MaterialGroup",
MG Mud User88f12472016-06-24 23:31:02 +0200835 QueryProp(P_MATERIAL), matgroup );
836}
837
838
Zesstra0265bd82018-11-28 20:42:24 +0100839public string MaterialList( int casus, mixed idinf )
MG Mud User88f12472016-06-24 23:31:02 +0200840{
Vanion50652322020-03-10 21:13:25 +0100841 return ({string})call_other( MATERIALDB, "ConvMaterialList",
MG Mud User88f12472016-06-24 23:31:02 +0200842 QueryProp(P_MATERIAL), casus, idinf );
843}
844
845static int _set_size(int sz) {
846//Groesse muss > 0 sein, alles andere ist unsinnig! (0 und neg. Groessen
847//haben keine phys. Relevanz und machen u.U. Probleme mit Objekten, die
848//Schaden in Abhaengigkeit der Groesse machen)
849 if (sz>0)
850 Set(P_SIZE,sz,F_VALUE);
851 return(Query(P_SIZE,F_VALUE));
852}
853
854// P_CLONE_TIME
855static int _query_clone_time() { return object_time(); }
856