blob: afc97c4c13718ffbafb0fe8d5a00331bbda1402b [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001/* -*- lpc -*- */
2//--------------------------------------------------------------------------
3//
4// morph.c
5//
6// (c) Troy (troy@mg.mud.de)
7// Kopieren, Veraendern oder Weitergabe: na klar, immer zu, je schlimmer
8// um so besser
9//
10// Objekt erstellt: 14.08.01, Troy
11//
12// Dieser shadow implementiert generische Verwandlungen. Im Gegensatz oder
13// in Ergänzung zum Tarnhelm sind diese nicht auf die Beschreibung
14// beschränkt, sondern schlagen sich auch in anderen Properties nieder.
15//
16//--------------------------------------------------------------------------
17
18#include <moving.h>
19#include <properties.h>
20#include <wizlevels.h>
21
22//--------------------------------------------------------------------------
23
24#pragma strong_types,save_types
25
26//--------------------------------------------------------------------------
27
28varargs int remove( int silent );
29
30//--------------------------------------------------------------------------
31//
32// Property-Einstellungen je nach Rasse
33//
34//--------------------------------------------------------------------------
35
36private mapping morph_properties;
37
38private object pl; // der schattierte Spieler
39
40//--------------------------------------------------------------------------
41//
42// start_shadow( Spieler, Properties )
43//
44// Startet das Shadowing von Spieler. Properties ist ein Mapping mit
45// den zu ändernden Properties. Dort nicht vorhandene Properties werden
46// zum Spieler durchgereicht. Es werden dort entweder einzelne Werte
47// erwartet (Beispiel: ([ P_GENDER: MALE ])), die dann für alle Rassen
48// gelten, oder closures, die dann ausgeführt werden unter Übergabe der
49// Spielerrasse als Parameter oder aber Mappings mit den Rassennamen
50// (Beispiel: ([ P_GENDER: ([ "Mensch": NEUTER, "Elf": FEMALE,
51// "Zwerg": MALE, ... ]) ])). Ist eine Rasse in dem Rassenmapping nicht
52// vorhanden, so wird das Property zum Spieler durchgereicht. Speziell
53// behandelt werden P_IDS (siehe _query_ids()) und P_NAME (siehe
54// _query_name()).
55//
56//--------------------------------------------------------------------------
57int start_shadow( object _pl, mapping preset )
58{
59 if ( !clonep( this_object() ) )
60 return 1;
61 if ( !_pl || !query_once_interactive( _pl ) )
62 return remove();
63 pl = _pl;
64 morph_properties = deep_copy( preset );
65 shadow( pl, 1 );
66 return 1;
67}
68
69//--------------------------------------------------------------------------
70//
71// stop_shadow()
72//
73// Beendet das Shadowing und zerstört dieses Objekt
74//
75//--------------------------------------------------------------------------
76int stop_shadow( /* void */ )
77{
78 if ( !clonep( this_object() ) )
79 return 0;
80 unshadow();
81 return remove();
82}
83
84//--------------------------------------------------------------------------
85//
86// _query_property( Property )
87//
88// Generische Property-Maskierung. liefert aus morph_properties den zur
89// Rasse des Trägers passenden Eintrag.
90//
91//--------------------------------------------------------------------------
92nomask static mixed _query_property( string prop )
93{
94 string race;
95
96 // Rasse holen.
97 if ( IS_LEARNER(pl) )
98 race = "Magier";
99 else // _query_race() ist notwendig, um closures zu umgehen.
100 race = pl->_query_race();
101
102 if ( member( morph_properties, prop ) == 0 )
103 return pl->Query( prop );
104 if ( closurep( morph_properties[ prop ] ) )
105 return funcall( morph_properties[ prop ], race );
106 if ( mappingp( morph_properties[ prop ] ) )
107 {
108 if ( member( morph_properties[ prop ], race ) == 0 )
109 return pl->Query( prop );
110 if ( closurep( morph_properties[ prop ][ race ] ) )
111 return funcall( morph_properties[ prop ][ race ] );
112
113 return morph_properties[ prop ][ race ];
114 }
115 return morph_properties[ prop ];
116}
117
118//--------------------------------------------------------------------------
119//
120// _query_article()
121//
122// Property-Maskierung für P_ARTICLE
123//
124//--------------------------------------------------------------------------
125int _query_article( /* void */ )
126{
127 return (int)_query_property( P_ARTICLE );
128}
129
130//--------------------------------------------------------------------------
131//
132// _query_average_size()
133//
134// Property-Maskierung für P_AVERAGE_SIZE
135//
136//--------------------------------------------------------------------------
137int _query_average_size( /* void */ )
138{
139 return (int)_query_property( P_AVERAGE_SIZE );
140}
141
142//--------------------------------------------------------------------------
143//
144// _query_average_weight()
145//
146// Property-Maskierung für P_AVERAGE_WEIGHT
147//
148//--------------------------------------------------------------------------
149int _query_average_weight( /* void */ )
150{
151 return (int)_query_property( P_AVERAGE_WEIGHT );
152}
153
154//--------------------------------------------------------------------------
155//
156// _query_body()
157//
158// Property-Maskierung für P_BODY
159//
160//--------------------------------------------------------------------------
161int _query_body( /* void */ )
162{
163 return (int)_query_property( P_BODY );
164}
165
166//--------------------------------------------------------------------------
167//
168// _query_gender()
169//
170// Property-Maskierung für P_GENDER
171//
172//--------------------------------------------------------------------------
173int _query_gender( /* void */ )
174{
175 return (int)_query_property( P_GENDER );
176}
177
178//--------------------------------------------------------------------------
179//
180// _query_hands()
181//
182// Property-Maskierung für P_HANDS
183//
184//--------------------------------------------------------------------------
185mixed _query_hands( /* void */ )
186{
187 return _query_property( P_HANDS );
188}
189
190//--------------------------------------------------------------------------
191//
192// _query_ids()
193//
194// Property-Maskierung für P_IDS - Nicht-Standard, da je nach Ursprungs-
195// geschlecht des Spielers zusätzliche ids fällig werden. Ablauf: Es gibt
196// 5 Schritte, bei deren jeweiligem Versagen die ids des Spielers durch-
197// gereicht werden:
198// 1. P_IDS ist im property-mapping vorhanden
199// 2. a) es ist ein string oder ein array: es wird an die ids des Spielers
200// angehängt und zurückgegeben.
201// b) es ist eine closure. Diese wird ausgeführt unter Übergabe der
202// Spieler-ids, der Rasse des Spielers und der Geschlechter
203// (dieses Objekts und des Spielers). Der Ergebniswert der closure
204// wird direkt zurückgegeben.
205// c) es ist ein mapping. Hier nehmen wir nun das übliche Rassennamen-
206// mapping an -> 3.)
207// 3. Für die Rasse des Spielers wird ein Eintrag gesucht
208// a) er ist ein string oder ein array: er wird an die ids des Spielers
209// angehängt und zurückgegeben.
210// b) er ist eine closure. Diese wird ausgeführt unter Übergabe der
211// Spieler-ids, der Rasse des Spielers und der Geschlechter
212// (dieses Objekts und des Spielers). Der Ergebniswert der closure
213// wird direkt zurückgegeben.
214// c) er ist ein mapping. Es wird angenommen, dass je Geschlecht DIESES
215// Objekts ein Eintrag vorhanden ist. -> 4.)
216// 4. Für das Geschlecht dieses Objekts wird ein Eintrag gesucht
217// a) er ist ein string oder ein array: er wird an die ids des Spielers
218// angehängt und zurückgegeben.
219// b) er ist eine closure. Diese wird ausgeführt unter Übergabe der
220// Spieler-ids, der Rasse des Spielers und der Geschlechter
221// (dieses Objekts und des Spielers). Der Ergebniswert der closure
222// wird direkt zurückgegeben.
223// c) er ist ein mapping. Es wird angenommen, dass je Geschlecht DES
224// Spielers ein Eintrag vorhanden ist. -> 5.)
225// 5. Für das Geschlecht des Spielers wird ein Eintrag gesucht
226// a) er ist ein string oder ein array: er wird an die ids des Spielers
227// angehängt und zurückgegeben.
228// b) er ist eine closure. Diese wird ausgeführt unter Übergabe der
229// Spieler-ids, der Rasse des Spielers und der Geschlechter
230// (dieses Objekts und des Spielers). Der Ergebniswert der closure
231// wird direkt zurückgegeben.
232//
233//--------------------------------------------------------------------------
234mixed _query_ids( /* void */ )
235{
236 string race;
237 mixed ids;
238 int gender, sgender;
239
240 // Test 1.
241 ids = pl->Query( P_IDS );
242 if ( member( morph_properties, P_IDS ) == 0 )
243 return ids;
244
245 // Rasse holen.
246 if ( IS_LEARNER(pl) )
247 race = "Magier";
248 else // _query_race() ist notwendig, um closures zu umgehen.
249 race = pl->_query_race();
250
251 // Geschlechter holen
252 gender = _query_gender();
253 sgender = pl->Query( P_GENDER );
254
255 // Test 2.
256 // string? Dann einfach den normalen ids dazu, genauso mit array
257 if ( stringp( morph_properties[ P_IDS ] ) )
258 return ids + ({ morph_properties[ P_IDS ] });
259 if ( pointerp( morph_properties[ P_IDS ] ) )
260 return ids + morph_properties[ P_IDS ];
261 if ( closurep( morph_properties[ P_IDS ] ) )
262 return funcall( morph_properties[ P_IDS ], ids, race, gender, sgender );
263 // falls kein mapping, dann raus
264 if ( !mappingp( morph_properties[ P_IDS ] ) )
265 return ids;
266
267 // Test 3.
268 if ( member( morph_properties[ P_IDS ], race ) == 0 )
269 return ids;
270 if ( stringp( morph_properties[ P_IDS ][ race ] ) )
271 return ids + ({ morph_properties[ P_IDS ][ race ] });
272 if ( pointerp( morph_properties[ P_IDS ][ race ] ) )
273 return ids + morph_properties[ P_IDS ][ race ];
274 if ( closurep( morph_properties[ P_IDS ][ race ] ) )
275 return funcall( morph_properties[ P_IDS ][ race ], ids, race, gender, sgender );
276 // falls kein mapping, dann raus
277 if ( !mappingp( morph_properties[ P_IDS ][ race ] ) )
278 return ids;
279
280 // Test 4.
281 if ( member( morph_properties[ P_IDS ][ race ], gender ) == 0 )
282 return ids;
283 if ( stringp( morph_properties[ P_IDS ][ race ][ gender ] ) )
284 return ids + ({ morph_properties[ P_IDS ][ race ][ gender ] });
285 if ( pointerp( morph_properties[ P_IDS ][ race ][ gender ] ) )
286 return ids + morph_properties[ P_IDS ][ race ][ gender ];
287 if ( closurep( morph_properties[ P_IDS ][ race ][ gender ] ) )
288 return funcall( morph_properties[ P_IDS ][ race ][ gender ],
289 ids, race, gender, sgender );
290 // falls kein mapping, dann raus
291 if ( !mappingp( morph_properties[ P_IDS ][ race ][ gender ] ) )
292 return ids;
293
294 // Test 5.
295 if ( member( morph_properties[ P_IDS ][ race ][ gender ], sgender ) == 0 )
296 return ids;
297 if ( stringp( morph_properties[ P_IDS ][ race ][ gender ][ sgender ] ) )
298 return ids + ({ morph_properties[ P_IDS ][ race ][ gender ][ sgender ] });
299 if ( pointerp( morph_properties[ P_IDS ][ race ][ gender ][ sgender ] ) )
300 return ids + morph_properties[ P_IDS ][ race ][ gender ][ sgender ];
301 if ( closurep( morph_properties[ P_IDS ][ race ][ gender ][ sgender ] ) )
302 return funcall( morph_properties[ P_IDS ][ race ][ gender ][ sgender ],
303 ids, race, gender, sgender );
304
305 return ids;
306}
307
308//--------------------------------------------------------------------------
309//
310// _query_is_morphed()
311//
312// Property-Methode für "is_morphed"
313//
314//--------------------------------------------------------------------------
315int _query_is_morphed( /* void */ )
316{
317 return 1;
318}
319
320//--------------------------------------------------------------------------
321//
322// _query_max_hands()
323//
324// Property-Maskierung für P_MAX_HANDS
325//
326//--------------------------------------------------------------------------
327int _query_max_hands( /* void */ )
328{
329 return (int)_query_property( P_MAX_HANDS );
330}
331
332//--------------------------------------------------------------------------
333//
334// _query_mmsgin()
335//
336// Property-Maskierung für P_MMSGIN
337//
338//--------------------------------------------------------------------------
339string _query_mmsgin( /* void */ )
340{
341 return (string)(_query_property( P_MMSGIN ) || "");
342}
343
344//--------------------------------------------------------------------------
345//
346// _query_mmsgout()
347//
348// Property-Maskierung für P_MMSGOUT
349//
350//--------------------------------------------------------------------------
351string _query_mmsgout( /* void */ )
352{
353 return (string)(_query_property( P_MMSGOUT ) || "");
354}
355
356//--------------------------------------------------------------------------
357//
358// _query_msgin()
359//
360// Property-Maskierung für P_MSGIN
361//
362//--------------------------------------------------------------------------
363string _query_msgin( /* void */ )
364{
365 return (string)(_query_property( P_MSGIN ) || "");
366}
367
368//--------------------------------------------------------------------------
369//
370// _query_msgout()
371//
372// Property-Maskierung für P_MSGOUT
373//
374//--------------------------------------------------------------------------
375string _query_msgout( /* void */ )
376{
377 return (string)(_query_property( P_MSGOUT ) || "");
378}
379
380//--------------------------------------------------------------------------
381//
382// _query_name()
383//
384// Property-Methode für P_NAME. Leider ist die player-shell so grottig,
385// dass überall angenommen wird, QueryProp(P_NAME) liefere einen String :-|
386// Vollständiges Property daher unter _query_name_full().
387//
388//--------------------------------------------------------------------------
389string _query_name( /* void */ )
390{
391 mixed prop;
392 prop = _query_property( P_NAME );
393 if ( stringp( prop ) )
394 return sprintf( prop, pl->Query( P_NAME ) );
395 if ( pointerp( prop ) )
396 return map( prop,
397 lambda( ({ 'el, 's }),
398 ({#'sprintf, 'el, 's}) ),
399 pl->Query( P_NAME ) )[ WER ];
400 return pl->Query( P_NAME );
401}
402
403//--------------------------------------------------------------------------
404//
405// _query_name_full()
406//
407// Property-Methode für "name_full".
408//
409//--------------------------------------------------------------------------
410mixed _query_name_full( /* void */ )
411{
412 mixed prop;
413 prop = _query_property( P_NAME );
414 if ( stringp( prop ) )
415 return sprintf( prop, pl->Query( P_NAME ) );
416 if ( pointerp( prop ) )
417 return map( prop,
418 lambda( ({ 'el, 's }),
419 ({#'sprintf, 'el, 's}) ),
420 pl->Query( P_NAME ) );
421 return pl->Query( P_NAME );
422}
423
424//--------------------------------------------------------------------------
425//
426// _query_presay()
427//
428// Property-Maskierung für P_PRESAY
429//
430//--------------------------------------------------------------------------
431string _query_presay( /* void */ )
432{
433 return (string)(_query_property( P_PRESAY ) || "");
434}
435
436//--------------------------------------------------------------------------
437//
438// _query_race()
439//
440// Property-Maskierung für P_RACE
441//
442//--------------------------------------------------------------------------
443string _query_race( /* void */ )
444{
445 return (string)(_query_property( P_RACE ) || "");
446}
447
448//--------------------------------------------------------------------------
449//
450// _query_racestring()
451//
452// Property-Maskierung für P_RACESTRING
453//
454//--------------------------------------------------------------------------
455string* _query_racestring( /* void */ )
456{
457 return (string*)_query_property( P_RACESTRING );
458}
459
460//--------------------------------------------------------------------------
461//
462// _query_size()
463//
464// Property-Maskierung für P_SIZE
465//
466//--------------------------------------------------------------------------
467int _query_size( /* void */ )
468{
469 return (int)_query_property( P_SIZE );
470}
471
472//--------------------------------------------------------------------------
473//
474// _query_title()
475//
476// Property-Maskierung für P_TITLE
477//
478//--------------------------------------------------------------------------
479string _query_title( /* void */ )
480{
481 return (string)(_query_property( P_TITLE ) || "");
482}
483
484//--------------------------------------------------------------------------
485//
486// _query_weight()
487//
488// Property-Maskierung für P_WEIGHT
489//
490//--------------------------------------------------------------------------
491int _query_weight( /* void */ )
492{
493 return (int)(_query_property( P_WEIGHT ) || "");
494}
495
496//--------------------------------------------------------------------------
497//
498// id( Text, Level)
499//
500// Die Identifizierung spinnt mit P_NAME-Arrays
501//
502//--------------------------------------------------------------------------
503varargs int id( string str, int lvl )
504{
505 string plname;
506
507 if ( pl->QueryProp( P_GHOST ) )
508 if ( str == "geist" )
509 return 1;
510 else if ( ( sscanf( str, "geist von %s", plname ) == 1 ) &&
511 pl->id( plname ) )
512 return 1;
513 else if ( ( sscanf( str, "geist %s", plname ) == 1 ) &&
514 pl->id( plname ) )
515 return 1;
516
517 return pl->id( str, lvl );
518}
519
520//--------------------------------------------------------------------------
521//
522// long()
523//
524// Die Langbeschreibung im Spieler hadert mit dem Geschlecht NEUTER...
525//
526//--------------------------------------------------------------------------
527varargs string long( /* void */ )
528{
529 string slong;
530 slong = pl->long();
531
532 if ( _query_gender() == NEUTER )
533 {
534 string *along;
535 int i;
536
537 // alle Er-s und er-s suchen...
538 along = regexplode( slong, "\\<[Ee]r\\>" );
539 // ... und das r durch ein s ersetzen.
540 for ( i = 1 ; i < sizeof( along ) ; i += 2 )
541 along[ i ][ 1 ] = 's';
542 slong = implode( along, "" );
543 }
544
545 return slong;
546}
547
548//--------------------------------------------------------------------------
549//
550// short()
551//
552// Die Kurzbeschreibung im Spieler hat ein Problem mit P_NAME-Arrays
553//
554//--------------------------------------------------------------------------
555string short( /* void */ )
556{
557 mixed names;
558 string answer;
559 string title;
560
561 if ( pl->QueryProp( P_INVIS ) )
562 if ( interactive( previous_object() ) &&
563 IS_LEARNING( previous_object() ) )
564 return "(" + pl->Query( P_NAME ) + ") \n";
565 else
566 return (string)0;
567
568 names = _query_name_full();
569 if ( stringp( names ) )
570 names = ({ names, names, names, names });
571
572 if ( pl->QueryProp( P_GHOST ) )
573 answer = "Der Geist " + pl->QueryArticle( WESSEN, 0 ) + names[ WESSEN ];
574 else
575 answer = pl->QueryArticle( WER, 0 ) + names[ WER ];
576 if ( ( title = pl->QueryProp( P_TITLE ) ) &&
577 ( title != "" ) )
578 answer += " " + title;
579 if ( !interactive( pl ) )
580 answer += " (netztot)";
581 return capitalize( answer ) + ".\n";
582}
583
584//--------------------------------------------------------------------------
585//
586// remove( Schnauze )
587//
588// aufräumen
589//
590//--------------------------------------------------------------------------
591varargs int remove( int silent )
592{
593 destruct( this_object() );
594 return 1;
595}
596
597//--------------------------------------------------------------------------
598// -- ENDE --