| // MorgenGrauen MUDlib |
| // |
| // thing/description.c -- description handling for standard objects |
| // |
| // $Id: description.c 9561 2016-05-25 19:33:22Z Zesstra $ |
| |
| #pragma strict_types |
| #pragma save_types |
| #pragma range_check |
| #pragma no_clone |
| #pragma pedantic |
| |
| #include <tls.h> |
| #include <thing/description.h> |
| #include <thing/material.h> |
| #include <thing/lighttypes.h> |
| #include <exploration.h> // wegen EPMASTER |
| #include <class.h> |
| |
| #define NEED_PROTOTYPES |
| #include <thing/properties.h> |
| #include <thing/language.h> |
| |
| #undef NEED_PROTOTYPES |
| #include <properties.h> |
| |
| // Variable um den FP abzuspeichern |
| private nosave mixed *explore; |
| |
| // Prototypen |
| public string short(); |
| public varargs string long(int mode); |
| |
| // ##################### |
| //######################## System-Funktionen ############################ |
| // ##################### |
| |
| // Objekt erzeugen |
| protected void create() |
| { |
| string poid, tpid; |
| object tp; |
| |
| SetProp( P_NAME, "Ding" ); |
| SetProp( P_SHORT, "Nichts besonderes" ); |
| SetProp( P_LONG, 0 ); |
| |
| Set( P_ADJECTIVES, ({}) ); |
| Set( P_NAME_ADJ, ({}) ); |
| Set( P_IDS, ({}) ); |
| Set( P_CLASS, ({}) ); |
| |
| Set( P_READ_DETAILS, ([]), F_VALUE); |
| Set( P_READ_DETAILS, SECURED|NOSETMETHOD, F_MODE_AS); |
| |
| Set( P_DETAILS, ([]), F_VALUE); |
| Set( P_DETAILS, SECURED|NOSETMETHOD, F_MODE_AS ); |
| |
| Set( P_SMELLS, ([]), F_VALUE); |
| Set( P_SMELLS, SECURED|NOSETMETHOD, F_MODE_AS ); |
| |
| Set( P_SOUNDS, ([]), F_VALUE); |
| Set( P_SOUNDS, SECURED|NOSETMETHOD, F_MODE_AS ); |
| |
| Set( P_TOUCH_DETAILS, ([]), F_VALUE); |
| Set( P_TOUCH_DETAILS, SECURED|NOSETMETHOD, F_MODE_AS ); |
| |
| // Aenderungen an dieser Prop sind tabu. |
| Set( P_CLONE_TIME, NOSETMETHOD|SECURED, F_MODE_AS ); |
| |
| // Id des Cloners und des Besitzers kommen nach P_CLONER |
| if (objectp( tp=this_interactive()||this_player() )) |
| { |
| tpid=geteuid(tp); |
| if (!(tpid=geteuid(tp))) tpid=getuid(tp); |
| } |
| else |
| tpid="UNKNOWN"; |
| |
| if (previous_object()) |
| { |
| if (!(poid = geteuid(previous_object()))) |
| poid = getuid(previous_object()); |
| } |
| else |
| poid="UNKNOWN"; |
| |
| Set( P_CLONER, (poid != tpid ? poid+":"+tpid: tpid) ); |
| Set( P_CLONER, NOSETMETHOD|SECURED, F_MODE_AS ); |
| |
| // Gibt es FPs ? |
| explore = (mixed *)EPMASTER->QueryExplore(); |
| |
| return; |
| } |
| |
| protected void create_super() { |
| set_next_reset(-1); |
| } |
| |
| // ################## |
| //######################### Forscherpunkte ############################## |
| // ################## |
| |
| // FP vergeben |
| static void GiveEP( int type, string key ) |
| { |
| //Abbruch, wenn vergebendes Objekt schon zerstoert ist. ACHTUNG: Auch |
| //diese Abfrage wuerde kein FP vergeben werden, wenn sich das Objekt im |
| //vergebenden Kommando zerstoert, da der Driver call_other() von zerstoerten |
| //Objekten ignoriert! |
| if (!objectp(this_object())) return; |
| if (this_player()) this_player()->countCmds( type, key ); |
| |
| if (explore&&!extern_call()&& |
| (explore[0] == type) && (member(explore[1], key) >= 0) ) |
| EPMASTER->GiveExplorationPoint(key); |
| return; |
| } |
| |
| // Manche Objekte koennen mit rename_object einen neuen Filenamen bekommen. |
| // Danach sollte der EPMASTER neu nach den Details befragt werden. |
| void __reload_explore() |
| { |
| explore = (mixed *)EPMASTER->QueryExplore(); |
| return; |
| } |
| |
| // ################# |
| //########################## ID-Management ############################## |
| // ################# |
| |
| // Gibt eine ID zurueck, die den Ladenamen, die aktuelle Kurzbeschreibung und |
| // die aktuelle Langbeschreibung beruecksichtigt. Diese ID ist ein Hashwert. |
| public string description_id() { |
| return hash(TLS_HASH_MD5, load_name() + short() + long()); |
| } |
| |
| /* Ids muessen uebergeben werden, da unit machmal mit plural-Ids, */ |
| /* also anderen als den normalen arbeiten muss. */ |
| int match_item( string str, string *ids ) |
| { |
| string *obj,*ads; |
| int len, i; |
| |
| // Parameter falsch? Passt nicht ... |
| if(!str) return 0; |
| if(!pointerp(ids)) return 0; |
| if(!sizeof(ids)) return 0; |
| |
| // Ist schon so dabei? Na Klasse :-) |
| if(member(ids,str)>-1) return 1; |
| |
| // Keine Adjektive vorhanden ... passt nicht. |
| if (!(ads=QueryProp(P_ADJECTIVES))) return 0; |
| if (!sizeof(ads)) return 0; |
| |
| // Nur ein Wort? Dann passt es nicht |
| obj=explode(str," "); |
| if (!(len=sizeof(obj)-1)) return 0; |
| |
| // Adjektive stehen am Anfang. Sobald es nicht mehr passt, |
| // muss es das Objektiv sein. |
| while(i<len&&member(ads,obj[i])>-1) i++; |
| |
| return (member(ids,implode(obj[i..len]," "))>-1); |
| } |
| |
| // Wird vom Gamedriver aufgerufen (present) |
| // Hat dieser Gegenstand die ID str? |
| // lvl wird ignoriert |
| varargs int id( string str, int lvl ) |
| { |
| string str2, tmp; |
| int count; |
| string|string* ids; |
| |
| // Kein Argument? Dann passt es nicht ... |
| if (!stringp(str)) return 0; |
| |
| // Keine IDs? Auch nicht gut ... |
| if (!pointerp(ids=QueryProp(P_IDS))) return 0; |
| if (!sizeof(ids)) return 0; |
| |
| ids += ({ ("\n" + object_name()), |
| ("\n" + explode(object_name(),"#")[0]) }); |
| |
| // Id passt? Alles klar :-) |
| if (match_item( str, ids )) return 1; |
| |
| // Die id hat eine Zahl drin. Wenn Zahl die Rohid passt, |
| // dann gucken, ob man selber das nte Element ist. |
| if (sscanf( str, "%s %d%s", str2, count, tmp)<2) return 0; |
| if (count<1) return 0; |
| if (sizeof(tmp)) return 0; |
| if (!match_item( str2, ids )) return 0; |
| if (!environment()) return 0; |
| return present(str2,count,environment())==this_object(); |
| } |
| |
| // Gleich eine ganze Liste von ids testen |
| int match_ids(string *list) |
| { |
| string *ids; |
| |
| // Ungueltige Parameter? Weg hier ... |
| if (!pointerp(list)) return 0; |
| if (!pointerp(ids=QueryProp(P_IDS))) return 0; |
| |
| ids += ({ ("\n" + object_name()), |
| ("\n" + explode(object_name(),"#")[0]) }); |
| |
| return sizeof( list & ids ); |
| } |
| |
| // ID hinzufuegen |
| void AddId( string|string* str ) |
| { |
| if (stringp(str)) str = ({ str }); |
| if (pointerp(str)) |
| // Doppelte eliminieren |
| Set( P_IDS, Query(P_IDS, F_VALUE)-str+str, F_VALUE); |
| return; |
| } |
| |
| // ID entfernen |
| void RemoveId(string|string* str) |
| { |
| if (stringp(str)) str = ({ str }); |
| if (pointerp(str)) |
| Set(P_IDS,Query(P_IDS, F_VALUE)-str, F_VALUE); |
| return; |
| } |
| |
| // Alle Ids auf einmal setzen |
| static string* _set_ids( string* ids ) |
| { |
| Set( P_IDS,({})); |
| AddId(ids); |
| return Query(P_IDS, F_VALUE); |
| } |
| |
| // Adjektiv hinzufuegen |
| void AddAdjective(string|string* str) |
| { |
| if (stringp(str)) str = ({ str }); |
| if (pointerp(str)) |
| // Doppelte eliminieren |
| Set( P_ADJECTIVES, Query(P_ADJECTIVES, F_VALUE)-str+str, F_VALUE ); |
| return; |
| } |
| |
| // Adjektiv entfernen |
| void RemoveAdjective(string|string* str) |
| { |
| if (stringp(str)) str = ({ str }); |
| if (pointerp(str)) |
| Set( P_ADJECTIVES, Query(P_ADJECTIVES, F_VALUE) - str, F_VALUE ); |
| return; |
| } |
| |
| // Alle Adjektive auf einmal setzen |
| static string* _set_adjectives(string* adjectives) |
| { |
| Set( P_ADJECTIVES,({}), F_VALUE); |
| AddAdjective(adjectives); |
| return Query(P_ADJECTIVES, F_VALUE); |
| } |
| |
| |
| // ################ |
| //########################## Namensgebung ############################### |
| // ################ |
| |
| // Im Fall von mehreren Adjektiven muessen diese mit komma |
| // zusamengebaut werden, dazu muss ich das leerzeichen aber erstmal |
| // abschneiden und so weiter ... |
| private string depointer_adj( string* adj, int casus, int demon ) { |
| string msg; |
| int start; |
| string res,a; |
| adj = map( adj, #'DeclAdj, casus, demon ); |
| start = 1; |
| res = ""; |
| foreach( a: adj ) { |
| res += (start ? "" : ", ") + a[0..<2]; |
| start = 0; |
| } |
| return res + " "; |
| } |
| |
| // Wie lautet der Name des Objekts? |
| varargs string name(int casus,int demon) |
| { |
| mixed sh, adj; |
| int art, plural; |
| |
| art = QueryProp(P_ARTICLE); |
| |
| // RAW: direkt zurueckgeben ohne Verarbeitung |
| if (casus == RAW ) |
| { |
| if(pointerp(QueryProp(P_NAME))) |
| return QueryProp(P_NAME)[WER]; |
| return QueryProp(P_NAME); |
| } |
| |
| // Unsichtbar: Etwas |
| if (QueryProp(P_INVIS)) |
| return ({ "etwas", "von etwas", "etwas", "etwas" })[casus]; |
| |
| // Kein Name? Schade ... |
| if (!(sh=QueryProp(P_NAME)) || |
| (stringp(sh) && !sizeof(sh))) return 0; |
| |
| // P_NAME pruefen. |
| if (pointerp(sh) && sizeof(sh) != 4) |
| raise_error(sprintf("Ungueltige Arraygroesse in P_NAME: %d\n", |
| sizeof(sh))); |
| |
| // Plural .. Namen verwursten |
| if (plural = QueryProp(P_PLURAL)) |
| { |
| // Selber Artikel suchen ist nicht ... |
| if (demon==2||!art) demon = 0; |
| |
| // falls P_NAME ein Array mit Faellen enthaelt, den richtigen |
| // extrahieren... |
| if (pointerp(sh)) { |
| sh = sh[casus]; |
| } |
| else { |
| // sonst versuchen, zu deklinieren. |
| int last = sh[<1]; |
| if (casus == WEM&&last!='s'&&last!='n') sh = sh + "n"; |
| } |
| |
| // Sind Adjektive vorhanden? |
| if ( pointerp(adj = QueryProp(P_NAME_ADJ)) && sizeof(adj)) |
| adj = depointer_adj(adj,casus,demon); |
| if (!stringp(adj)) adj = ""; |
| |
| return sprintf("%s%s%s%s",QueryArticle(casus,demon,0),adj, |
| (plural < 2 ? "":(plural < 8 ? |
| ({ "zwei ", "drei ", "vier ", "fuenf ", "sechs ", |
| "sieben " })[plural-2] : to_string(plural)+" ")),sh); |
| } |
| |
| // Name ist Pointer: Einfach den richtigen auswaehlen |
| if (pointerp(sh)) |
| sh = sh[casus]; |
| |
| // Ansonsten doch wieder verwursten ... |
| else if (stringp(sh)) |
| { |
| int last = sh[<1]; |
| |
| switch(casus) |
| { |
| case WEM: |
| case WEN: |
| if ( art && last=='e'&&QueryProp(P_GENDER) == MALE) |
| sh = (string)sh + "n"; |
| break; |
| |
| case WESSEN: |
| if( !art ) |
| { |
| switch(last) |
| { |
| case 'x': |
| case 's': |
| case 'z': |
| sh = (string)sh + "'"; |
| break; |
| |
| default: |
| sh = (string)sh + "s"; |
| } |
| } |
| else |
| { |
| switch(last) |
| { |
| default: |
| if (QueryProp(P_GENDER)!=FEMALE) |
| sh=(string)sh+"s"; |
| break; |
| case 'e': |
| if (QueryProp(P_GENDER)==MALE) |
| sh=(string)sh+"n"; |
| case 'x': |
| case 's': |
| case 'z': |
| break; |
| } /* switch (last) */ |
| } /* if( !art ) else */ |
| } /* switch( casus ) */ |
| } /* pointerp(sh) */ |
| |
| // RAW? Dann mal zurueck |
| if (demon == RAW) return (string)sh; |
| |
| // Selber Artikel suchen ... |
| if (demon==2) |
| { |
| if (art) |
| demon = SuggestArticle(); |
| else |
| demon=0; // Kein Artikel: egal (SuggestArticle ist zeitaufwendig) |
| } |
| |
| if (pointerp(adj = QueryProp(P_NAME_ADJ)) && sizeof(adj)) |
| adj = depointer_adj(adj,casus,demon); |
| |
| if (!stringp(adj)) adj = ""; |
| |
| return QueryArticle( casus, demon )+adj+sh; |
| } |
| |
| // Grossgeschriebenen Namen zurueckgeben |
| varargs string Name( int casus, int demon ) |
| { |
| return capitalize(name( casus, demon )||""); |
| } |
| |
| // Langbeschreibung anzeigen |
| public varargs string long(int mode) |
| { |
| return process_string( QueryProp(P_LONG) ); |
| } |
| |
| // Kurzbeschreibung anzeigen, falls nicht unsichtbar |
| public string short() |
| { |
| string sh; |
| |
| // Unsichtbar? Dann gibts nichts zu sehen ... |
| if (QueryProp(P_INVIS)||!(sh=QueryProp(P_SHORT))) |
| return 0; |
| |
| return process_string(sh)+".\n"; |
| } |
| |
| // Namens-Adjektive setzen |
| static string* _set_name_adj(string|string* adjectives) |
| { |
| if (!adjectives) |
| adjectives=({}); |
| // In Array umwandeln |
| else if ( !pointerp(adjectives)) |
| adjectives = ({ to_string(adjectives) }); |
| return Set( P_NAME_ADJ, adjectives ); |
| } |
| |
| // ############################ |
| //#################### Details, Gerueche, Laerm ######################### |
| // ############################ |
| |
| // Low-level Funktion zum Ergaenzen von Details, wird von den div. Add...() |
| // gerufen, die das richtige Mapping uebergeben. |
| // Aendert das Mapping <details> direkt. |
| private void _add_details(string|string* keys, |
| string|string*|mapping|closure descr, |
| mapping details ) |
| { |
| if (stringp(keys)) |
| details[keys]=descr; |
| else if (pointerp(keys)) |
| { |
| foreach(string key : keys) |
| details[lower_case(key)]=descr; |
| } |
| else |
| raise_error("Wrong type to argument 1, expected string|string*.\n"); |
| } |
| |
| // Low-level Funktion zum Entfernen von Details, wird von den div. Remove...() |
| // gerufen, die das richtige Mapping uebergeben. |
| // Aendert das Mapping <details> direkt. |
| private void _remove_details(string|string* keys, mapping details ) |
| { |
| if (stringp(keys)) |
| details -= ([keys]); |
| else if (pointerp(keys)) |
| details -= mkmapping(keys); |
| else |
| raise_error("Wrong type to argument 1, expected string|string*.\n"); |
| } |
| |
| // Detail(s) hinzufuegen |
| void AddDetail(string|string* keys, string|string*|mapping|closure descr) |
| { |
| int i; |
| mapping details; |
| |
| details = Query(P_DETAILS, F_VALUE); |
| |
| // _add_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| return _add_details(keys, descr, details); |
| } |
| |
| // Detail(s) entfernen |
| varargs void RemoveDetail(string|string* keys ) |
| { |
| // Alle loeschen geht direkt ... |
| if (!keys ) |
| Set(P_DETAILS, ([]), F_VALUE); |
| else |
| // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| _remove_details(keys, Query(P_DETAILS, F_VALUE)); |
| } |
| |
| // SpecialDetail hinzufuegen |
| void AddSpecialDetail(string|string* keys, string functionname ) |
| { |
| closure cl; |
| |
| // Absichern! Sonst koennte jeder interne Funktionen aufrufen |
| if (extern_call() && |
| (geteuid(previous_object()) != geteuid() || process_call()) && |
| !(object_name(previous_object()) == "/obj/doormaster" && |
| functionname == "special_detail_doors") ) |
| raise_error( "Illegal use of AddSpecialDetail!\n" ); |
| |
| // Closure generieren |
| if ( !stringp(functionname)|| |
| !(cl = symbol_function( functionname, this_object())) ) |
| return; |
| |
| // Detail hinzufuegen |
| AddDetail( keys, cl ); |
| return; |
| } |
| |
| // SpecialDetail(s) entfernen |
| void RemoveSpecialDetail(string|string* keys ) |
| { |
| // RemoveSpecialDetail(0) wuerde sonst ALLE Details (auch die |
| // 'normalen') loeschen |
| if (pointerp(keys)||stringp(keys)) |
| RemoveDetail(keys); |
| return; |
| } |
| |
| // Lesbares Detail einfuegen |
| void AddReadDetail(string|string* keys, |
| string|string*|mapping|closure descr ) |
| { |
| // _add_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| return _add_details(keys, descr, Query(P_READ_DETAILS, F_VALUE)); |
| } |
| |
| // Lesbare(s) Detail(s) entfernen |
| varargs void RemoveReadDetail(string|string* keys ) |
| { |
| // Alle loeschen geht direkt ... |
| if (!keys ) |
| Set(P_READ_DETAILS, ([]), F_VALUE); |
| else |
| // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| _remove_details(keys, Query(P_READ_DETAILS, F_VALUE)); |
| } |
| |
| // Geraeusch(e) dazufuegen |
| void AddSounds(string|string* keys, |
| string|string*|mapping|closure descr ) |
| { |
| // _add_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| return _add_details(keys, descr, Query(P_SOUNDS, F_VALUE)); |
| } |
| |
| // Geraeusch(e) entfernen |
| varargs void RemoveSounds(string|string* keys ) |
| { |
| // Alle loeschen geht direkt ... |
| if (!keys ) |
| Set(P_SOUNDS, ([]), F_VALUE); |
| else |
| // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| _remove_details(keys, Query(P_SOUNDS, F_VALUE)); |
| } |
| |
| // Geru(e)ch(e) hinzufuegen |
| void AddSmells(string|string* keys, |
| string|string*|mapping|closure descr ) |
| { |
| // _add_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| return _add_details(keys, descr, Query(P_SMELLS, F_VALUE)); |
| } |
| |
| // Geru(e)ch(e) entfernen |
| varargs void RemoveSmells(string|string* keys ) |
| { |
| // Alle loeschen geht direkt ... |
| if (!keys ) |
| Set(P_SMELLS, ([]), F_VALUE); |
| else |
| // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| _remove_details(keys, Query(P_SMELLS, F_VALUE)); |
| } |
| |
| // Tastbare(s) Detail(s) hinzufuegen |
| void AddTouchDetail(string|string* keys, |
| string|string*|mapping|closure descr ) |
| { |
| // _add_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| return _add_details(keys, descr, Query(P_TOUCH_DETAILS, F_VALUE)); |
| } |
| |
| // Tastbare(s) Detail(s) entfernen |
| varargs void RemoveTouchDetails(string|string* keys ) |
| { |
| // Alle loeschen geht direkt ... |
| if (!keys ) |
| Set(P_TOUCH_DETAILS, ([]), F_VALUE); |
| else |
| // _remove_details() aendern das Mapping direkt, Set etc. nicht noetig. |
| _remove_details(keys, Query(P_TOUCH_DETAILS, F_VALUE)); |
| } |
| |
| // Detailinfos fuer Detail key, Spieler hat die Rasse race |
| // und benutzt seinen Sinn sense |
| varargs string GetDetail(string key, string race, int sense) |
| { |
| string|string*|mapping|closure detail; |
| |
| if (stringp(race)) race = lower_case(race); |
| |
| switch(sense) |
| { |
| case SENSE_SMELL: detail=Query(P_SMELLS, F_VALUE)[key]; |
| sense=EP_SMELL; break; |
| case SENSE_SOUND: detail=Query(P_SOUNDS, F_VALUE)[key]; |
| sense=EP_SOUND; break; |
| case SENSE_TOUCH: detail=Query(P_TOUCH_DETAILS, F_VALUE)[key]; |
| sense=EP_TOUCH; break; |
| case SENSE_READ: detail=Query(P_READ_DETAILS, F_VALUE)[key]; |
| sense=EP_RDET; |
| break; |
| |
| default: detail=Query(P_DETAILS, F_VALUE)[key]; |
| sense=EP_DETAIL; break; |
| } |
| |
| if (!stringp(detail)) |
| { |
| if (closurep(detail)) |
| detail = (string)funcall(detail,key); |
| else if (mappingp(detail)) |
| detail = (string)(detail[race]||detail[0]); |
| else if (pointerp(detail)) |
| detail = (string)(detail[random(sizeof(detail))]); |
| } |
| |
| // FP vergeben (so vorhanden ;-) ) |
| if (detail) GiveEP(sense,key); |
| |
| return detail; |
| } |
| |
| // TODO: OBSOLET (Libgrep notwendig) |
| void read( string str ) { |
| raise_error("Diese Funktion existiert nicht mehr.\n"); |
| } |
| |
| |
| // ###################### |
| //####################### Zugriffsfunktionen ############################ |
| // ###################### |
| |
| // Dienen dazu, die direkte Manipulation der Props von aussen zu erschweren. |
| |
| // Filter, um Specialdetails zu eliminieren |
| // erstellt ausserdem ne Kopie vom Mapping. (Wichtig!) |
| // Wird vor allem benoetigt, um P_DETAILS in P_DETAILS und |
| // P_SPECIAL_DETAILS zu treffen. |
| private int _closures(string x, mapping details, int yes ) |
| { |
| return yes ? closurep(details[x]) : !closurep(details[x]); |
| } |
| |
| static mapping _query_details() |
| { |
| return filter_indices(Query(P_DETAILS, F_VALUE), #'_closures, |
| Query(P_DETAILS, F_VALUE),0); |
| } |
| |
| static mapping _query_special_details() |
| { |
| return filter_indices(Query(P_DETAILS, F_VALUE),#'_closures, |
| Query(P_DETAILS, F_VALUE),1); |
| } |
| |
| static mapping _query_read_details() { |
| return deep_copy(Query(P_READ_DETAILS, F_VALUE)); |
| } |
| |
| static mapping _query_sound_details() { |
| return deep_copy(Query(P_SOUNDS, F_VALUE)); |
| } |
| |
| static mapping _query_smell_details() { |
| return deep_copy(Query(P_SMELLS, F_VALUE)); |
| } |
| |
| |
| // ########################## |
| //##################### Klassen-Mitgliedschaft ########################## |
| // ########################## |
| |
| // Klasse hinzufuegen |
| public void AddClass(string|string* str) |
| { |
| if (stringp(str)) |
| str = ({ str }); |
| // Aliase aufloesen und implizite Klassen addieren. |
| str = (string*)CLASSDB->AddImplicitClasses(str); |
| // Summe mit alten Klassen bilden und Doppelte eliminieren |
| str = str + Query(P_CLASS, F_VALUE); |
| Set( P_CLASS, m_indices(mkmapping(str)), F_VALUE); |
| |
| return; |
| } |
| |
| // Klasse entfernen |
| void RemoveClass(string|string* str) |
| { |
| if (stringp(str)) |
| str = ({ str }); |
| |
| // Aliase aufloesen und implizite Klassen addieren. |
| str = (string*)CLASSDB->AddImplicitClasses(str); |
| |
| // Und alle - inklusive impliziter Klassen - entfernen |
| // TODO: Pruefen, ob dies die richtige Entscheidung ist. |
| Set( P_CLASS, Query(P_CLASS, F_VALUE)-str, F_VALUE); |
| |
| return; |
| } |
| |
| // Ist das Objekt Mitglied der Klasse str? |
| int is_class_member(string|string* str) |
| { |
| // Keine Klasse, keine Mitgliedschaft ... |
| if (!str || str=="") |
| return 0; |
| |
| // Es sollte schon ein Array sein |
| if (stringp(str)) |
| str = ({ str }); |
| |
| // Klassen und Ids ins Array |
| string *classes=QueryProp(P_CLASS); |
| if (!pointerp(classes)) |
| return 0; |
| |
| // .. und testen |
| foreach(string class : str) |
| if (member(classes,class) > -1 ) return 1; |
| |
| return 0; |
| } |
| |
| // Klasse direkt setzen abfangen |
| static string* _set_class(string* classes ) |
| { |
| Set( P_CLASS, ({}), F_VALUE ); |
| AddClass(classes); |
| return QueryProp(P_CLASS); |
| } |
| |
| // ##################### |
| //######################## Material-Handling ############################ |
| // ##################### |
| |
| // Material setzen |
| static mapping _set_material(mapping|string|string* mat ) |
| { |
| mapping mats = ([]); |
| |
| if (mappingp(mat)) |
| { |
| if( !sizeof(mat) || !widthof(mat) ) |
| raise_error(sprintf("P_MATERIAL: expected mapping with at least one " |
| "key and one value, got %.50O\n",mat)); |
| else |
| mats = mat; |
| } |
| else if (stringp(mat)) |
| mats[mat]=100; |
| else |
| { |
| int sz = sizeof(mat); |
| // Kommt dann vor, wenn <mat> 0 oder ({}) ist. |
| if ( !sz ) |
| raise_error(sprintf("P_MATERIAL: expected string or non-empty " |
| "mapping|string*, got %.50O.\n", mat)); |
| mats = mkmapping(mat, allocate(sz, 100/sz)); |
| } |
| return Set( P_MATERIAL, mats, F_VALUE ); |
| } |
| |
| // Woraus besteht das Objekt? |
| static mapping _query_material() |
| { |
| mixed res; |
| |
| if ( !mappingp(res = Query(P_MATERIAL, F_VALUE)) ) |
| return ([MAT_MISC:100]); |
| |
| return res; |
| } |
| |
| // Anteil von mat am Objekt? |
| int QueryMaterial( string mat ) |
| { |
| mapping mats; |
| |
| if ( !mappingp(mats = QueryProp(P_MATERIAL)) ) |
| return 0; |
| |
| return mats[mat]; |
| } |
| |
| // Anteil der Gruppe am Objekt |
| int QueryMaterialGroup( string matgroup ) |
| { |
| return (int)call_other( MATERIALDB, "MaterialGroup", |
| QueryProp(P_MATERIAL), matgroup ); |
| } |
| |
| |
| string MaterialList( int casus, mixed idinf ) |
| { |
| return (string)call_other( MATERIALDB, "ConvMaterialList", |
| QueryProp(P_MATERIAL), casus, idinf ); |
| } |
| |
| static int _set_size(int sz) { |
| //Groesse muss > 0 sein, alles andere ist unsinnig! (0 und neg. Groessen |
| //haben keine phys. Relevanz und machen u.U. Probleme mit Objekten, die |
| //Schaden in Abhaengigkeit der Groesse machen) |
| if (sz>0) |
| Set(P_SIZE,sz,F_VALUE); |
| return(Query(P_SIZE,F_VALUE)); |
| } |
| |
| // P_CLONE_TIME |
| static int _query_clone_time() { return object_time(); } |
| |