blob: afc97c4c13718ffbafb0fe8d5a00331bbda1402b [file] [log] [blame]
/* -*- lpc -*- */
//--------------------------------------------------------------------------
//
// morph.c
//
// (c) Troy (troy@mg.mud.de)
// Kopieren, Veraendern oder Weitergabe: na klar, immer zu, je schlimmer
// um so besser
//
// Objekt erstellt: 14.08.01, Troy
//
// Dieser shadow implementiert generische Verwandlungen. Im Gegensatz oder
// in Ergänzung zum Tarnhelm sind diese nicht auf die Beschreibung
// beschränkt, sondern schlagen sich auch in anderen Properties nieder.
//
//--------------------------------------------------------------------------
#include <moving.h>
#include <properties.h>
#include <wizlevels.h>
//--------------------------------------------------------------------------
#pragma strong_types,save_types
//--------------------------------------------------------------------------
varargs int remove( int silent );
//--------------------------------------------------------------------------
//
// Property-Einstellungen je nach Rasse
//
//--------------------------------------------------------------------------
private mapping morph_properties;
private object pl; // der schattierte Spieler
//--------------------------------------------------------------------------
//
// start_shadow( Spieler, Properties )
//
// Startet das Shadowing von Spieler. Properties ist ein Mapping mit
// den zu ändernden Properties. Dort nicht vorhandene Properties werden
// zum Spieler durchgereicht. Es werden dort entweder einzelne Werte
// erwartet (Beispiel: ([ P_GENDER: MALE ])), die dann für alle Rassen
// gelten, oder closures, die dann ausgeführt werden unter Übergabe der
// Spielerrasse als Parameter oder aber Mappings mit den Rassennamen
// (Beispiel: ([ P_GENDER: ([ "Mensch": NEUTER, "Elf": FEMALE,
// "Zwerg": MALE, ... ]) ])). Ist eine Rasse in dem Rassenmapping nicht
// vorhanden, so wird das Property zum Spieler durchgereicht. Speziell
// behandelt werden P_IDS (siehe _query_ids()) und P_NAME (siehe
// _query_name()).
//
//--------------------------------------------------------------------------
int start_shadow( object _pl, mapping preset )
{
if ( !clonep( this_object() ) )
return 1;
if ( !_pl || !query_once_interactive( _pl ) )
return remove();
pl = _pl;
morph_properties = deep_copy( preset );
shadow( pl, 1 );
return 1;
}
//--------------------------------------------------------------------------
//
// stop_shadow()
//
// Beendet das Shadowing und zerstört dieses Objekt
//
//--------------------------------------------------------------------------
int stop_shadow( /* void */ )
{
if ( !clonep( this_object() ) )
return 0;
unshadow();
return remove();
}
//--------------------------------------------------------------------------
//
// _query_property( Property )
//
// Generische Property-Maskierung. liefert aus morph_properties den zur
// Rasse des Trägers passenden Eintrag.
//
//--------------------------------------------------------------------------
nomask static mixed _query_property( string prop )
{
string race;
// Rasse holen.
if ( IS_LEARNER(pl) )
race = "Magier";
else // _query_race() ist notwendig, um closures zu umgehen.
race = pl->_query_race();
if ( member( morph_properties, prop ) == 0 )
return pl->Query( prop );
if ( closurep( morph_properties[ prop ] ) )
return funcall( morph_properties[ prop ], race );
if ( mappingp( morph_properties[ prop ] ) )
{
if ( member( morph_properties[ prop ], race ) == 0 )
return pl->Query( prop );
if ( closurep( morph_properties[ prop ][ race ] ) )
return funcall( morph_properties[ prop ][ race ] );
return morph_properties[ prop ][ race ];
}
return morph_properties[ prop ];
}
//--------------------------------------------------------------------------
//
// _query_article()
//
// Property-Maskierung für P_ARTICLE
//
//--------------------------------------------------------------------------
int _query_article( /* void */ )
{
return (int)_query_property( P_ARTICLE );
}
//--------------------------------------------------------------------------
//
// _query_average_size()
//
// Property-Maskierung für P_AVERAGE_SIZE
//
//--------------------------------------------------------------------------
int _query_average_size( /* void */ )
{
return (int)_query_property( P_AVERAGE_SIZE );
}
//--------------------------------------------------------------------------
//
// _query_average_weight()
//
// Property-Maskierung für P_AVERAGE_WEIGHT
//
//--------------------------------------------------------------------------
int _query_average_weight( /* void */ )
{
return (int)_query_property( P_AVERAGE_WEIGHT );
}
//--------------------------------------------------------------------------
//
// _query_body()
//
// Property-Maskierung für P_BODY
//
//--------------------------------------------------------------------------
int _query_body( /* void */ )
{
return (int)_query_property( P_BODY );
}
//--------------------------------------------------------------------------
//
// _query_gender()
//
// Property-Maskierung für P_GENDER
//
//--------------------------------------------------------------------------
int _query_gender( /* void */ )
{
return (int)_query_property( P_GENDER );
}
//--------------------------------------------------------------------------
//
// _query_hands()
//
// Property-Maskierung für P_HANDS
//
//--------------------------------------------------------------------------
mixed _query_hands( /* void */ )
{
return _query_property( P_HANDS );
}
//--------------------------------------------------------------------------
//
// _query_ids()
//
// Property-Maskierung für P_IDS - Nicht-Standard, da je nach Ursprungs-
// geschlecht des Spielers zusätzliche ids fällig werden. Ablauf: Es gibt
// 5 Schritte, bei deren jeweiligem Versagen die ids des Spielers durch-
// gereicht werden:
// 1. P_IDS ist im property-mapping vorhanden
// 2. a) es ist ein string oder ein array: es wird an die ids des Spielers
// angehängt und zurückgegeben.
// b) es ist eine closure. Diese wird ausgeführt unter Übergabe der
// Spieler-ids, der Rasse des Spielers und der Geschlechter
// (dieses Objekts und des Spielers). Der Ergebniswert der closure
// wird direkt zurückgegeben.
// c) es ist ein mapping. Hier nehmen wir nun das übliche Rassennamen-
// mapping an -> 3.)
// 3. Für die Rasse des Spielers wird ein Eintrag gesucht
// a) er ist ein string oder ein array: er wird an die ids des Spielers
// angehängt und zurückgegeben.
// b) er ist eine closure. Diese wird ausgeführt unter Übergabe der
// Spieler-ids, der Rasse des Spielers und der Geschlechter
// (dieses Objekts und des Spielers). Der Ergebniswert der closure
// wird direkt zurückgegeben.
// c) er ist ein mapping. Es wird angenommen, dass je Geschlecht DIESES
// Objekts ein Eintrag vorhanden ist. -> 4.)
// 4. Für das Geschlecht dieses Objekts wird ein Eintrag gesucht
// a) er ist ein string oder ein array: er wird an die ids des Spielers
// angehängt und zurückgegeben.
// b) er ist eine closure. Diese wird ausgeführt unter Übergabe der
// Spieler-ids, der Rasse des Spielers und der Geschlechter
// (dieses Objekts und des Spielers). Der Ergebniswert der closure
// wird direkt zurückgegeben.
// c) er ist ein mapping. Es wird angenommen, dass je Geschlecht DES
// Spielers ein Eintrag vorhanden ist. -> 5.)
// 5. Für das Geschlecht des Spielers wird ein Eintrag gesucht
// a) er ist ein string oder ein array: er wird an die ids des Spielers
// angehängt und zurückgegeben.
// b) er ist eine closure. Diese wird ausgeführt unter Übergabe der
// Spieler-ids, der Rasse des Spielers und der Geschlechter
// (dieses Objekts und des Spielers). Der Ergebniswert der closure
// wird direkt zurückgegeben.
//
//--------------------------------------------------------------------------
mixed _query_ids( /* void */ )
{
string race;
mixed ids;
int gender, sgender;
// Test 1.
ids = pl->Query( P_IDS );
if ( member( morph_properties, P_IDS ) == 0 )
return ids;
// Rasse holen.
if ( IS_LEARNER(pl) )
race = "Magier";
else // _query_race() ist notwendig, um closures zu umgehen.
race = pl->_query_race();
// Geschlechter holen
gender = _query_gender();
sgender = pl->Query( P_GENDER );
// Test 2.
// string? Dann einfach den normalen ids dazu, genauso mit array
if ( stringp( morph_properties[ P_IDS ] ) )
return ids + ({ morph_properties[ P_IDS ] });
if ( pointerp( morph_properties[ P_IDS ] ) )
return ids + morph_properties[ P_IDS ];
if ( closurep( morph_properties[ P_IDS ] ) )
return funcall( morph_properties[ P_IDS ], ids, race, gender, sgender );
// falls kein mapping, dann raus
if ( !mappingp( morph_properties[ P_IDS ] ) )
return ids;
// Test 3.
if ( member( morph_properties[ P_IDS ], race ) == 0 )
return ids;
if ( stringp( morph_properties[ P_IDS ][ race ] ) )
return ids + ({ morph_properties[ P_IDS ][ race ] });
if ( pointerp( morph_properties[ P_IDS ][ race ] ) )
return ids + morph_properties[ P_IDS ][ race ];
if ( closurep( morph_properties[ P_IDS ][ race ] ) )
return funcall( morph_properties[ P_IDS ][ race ], ids, race, gender, sgender );
// falls kein mapping, dann raus
if ( !mappingp( morph_properties[ P_IDS ][ race ] ) )
return ids;
// Test 4.
if ( member( morph_properties[ P_IDS ][ race ], gender ) == 0 )
return ids;
if ( stringp( morph_properties[ P_IDS ][ race ][ gender ] ) )
return ids + ({ morph_properties[ P_IDS ][ race ][ gender ] });
if ( pointerp( morph_properties[ P_IDS ][ race ][ gender ] ) )
return ids + morph_properties[ P_IDS ][ race ][ gender ];
if ( closurep( morph_properties[ P_IDS ][ race ][ gender ] ) )
return funcall( morph_properties[ P_IDS ][ race ][ gender ],
ids, race, gender, sgender );
// falls kein mapping, dann raus
if ( !mappingp( morph_properties[ P_IDS ][ race ][ gender ] ) )
return ids;
// Test 5.
if ( member( morph_properties[ P_IDS ][ race ][ gender ], sgender ) == 0 )
return ids;
if ( stringp( morph_properties[ P_IDS ][ race ][ gender ][ sgender ] ) )
return ids + ({ morph_properties[ P_IDS ][ race ][ gender ][ sgender ] });
if ( pointerp( morph_properties[ P_IDS ][ race ][ gender ][ sgender ] ) )
return ids + morph_properties[ P_IDS ][ race ][ gender ][ sgender ];
if ( closurep( morph_properties[ P_IDS ][ race ][ gender ][ sgender ] ) )
return funcall( morph_properties[ P_IDS ][ race ][ gender ][ sgender ],
ids, race, gender, sgender );
return ids;
}
//--------------------------------------------------------------------------
//
// _query_is_morphed()
//
// Property-Methode für "is_morphed"
//
//--------------------------------------------------------------------------
int _query_is_morphed( /* void */ )
{
return 1;
}
//--------------------------------------------------------------------------
//
// _query_max_hands()
//
// Property-Maskierung für P_MAX_HANDS
//
//--------------------------------------------------------------------------
int _query_max_hands( /* void */ )
{
return (int)_query_property( P_MAX_HANDS );
}
//--------------------------------------------------------------------------
//
// _query_mmsgin()
//
// Property-Maskierung für P_MMSGIN
//
//--------------------------------------------------------------------------
string _query_mmsgin( /* void */ )
{
return (string)(_query_property( P_MMSGIN ) || "");
}
//--------------------------------------------------------------------------
//
// _query_mmsgout()
//
// Property-Maskierung für P_MMSGOUT
//
//--------------------------------------------------------------------------
string _query_mmsgout( /* void */ )
{
return (string)(_query_property( P_MMSGOUT ) || "");
}
//--------------------------------------------------------------------------
//
// _query_msgin()
//
// Property-Maskierung für P_MSGIN
//
//--------------------------------------------------------------------------
string _query_msgin( /* void */ )
{
return (string)(_query_property( P_MSGIN ) || "");
}
//--------------------------------------------------------------------------
//
// _query_msgout()
//
// Property-Maskierung für P_MSGOUT
//
//--------------------------------------------------------------------------
string _query_msgout( /* void */ )
{
return (string)(_query_property( P_MSGOUT ) || "");
}
//--------------------------------------------------------------------------
//
// _query_name()
//
// Property-Methode für P_NAME. Leider ist die player-shell so grottig,
// dass überall angenommen wird, QueryProp(P_NAME) liefere einen String :-|
// Vollständiges Property daher unter _query_name_full().
//
//--------------------------------------------------------------------------
string _query_name( /* void */ )
{
mixed prop;
prop = _query_property( P_NAME );
if ( stringp( prop ) )
return sprintf( prop, pl->Query( P_NAME ) );
if ( pointerp( prop ) )
return map( prop,
lambda( ({ 'el, 's }),
({#'sprintf, 'el, 's}) ),
pl->Query( P_NAME ) )[ WER ];
return pl->Query( P_NAME );
}
//--------------------------------------------------------------------------
//
// _query_name_full()
//
// Property-Methode für "name_full".
//
//--------------------------------------------------------------------------
mixed _query_name_full( /* void */ )
{
mixed prop;
prop = _query_property( P_NAME );
if ( stringp( prop ) )
return sprintf( prop, pl->Query( P_NAME ) );
if ( pointerp( prop ) )
return map( prop,
lambda( ({ 'el, 's }),
({#'sprintf, 'el, 's}) ),
pl->Query( P_NAME ) );
return pl->Query( P_NAME );
}
//--------------------------------------------------------------------------
//
// _query_presay()
//
// Property-Maskierung für P_PRESAY
//
//--------------------------------------------------------------------------
string _query_presay( /* void */ )
{
return (string)(_query_property( P_PRESAY ) || "");
}
//--------------------------------------------------------------------------
//
// _query_race()
//
// Property-Maskierung für P_RACE
//
//--------------------------------------------------------------------------
string _query_race( /* void */ )
{
return (string)(_query_property( P_RACE ) || "");
}
//--------------------------------------------------------------------------
//
// _query_racestring()
//
// Property-Maskierung für P_RACESTRING
//
//--------------------------------------------------------------------------
string* _query_racestring( /* void */ )
{
return (string*)_query_property( P_RACESTRING );
}
//--------------------------------------------------------------------------
//
// _query_size()
//
// Property-Maskierung für P_SIZE
//
//--------------------------------------------------------------------------
int _query_size( /* void */ )
{
return (int)_query_property( P_SIZE );
}
//--------------------------------------------------------------------------
//
// _query_title()
//
// Property-Maskierung für P_TITLE
//
//--------------------------------------------------------------------------
string _query_title( /* void */ )
{
return (string)(_query_property( P_TITLE ) || "");
}
//--------------------------------------------------------------------------
//
// _query_weight()
//
// Property-Maskierung für P_WEIGHT
//
//--------------------------------------------------------------------------
int _query_weight( /* void */ )
{
return (int)(_query_property( P_WEIGHT ) || "");
}
//--------------------------------------------------------------------------
//
// id( Text, Level)
//
// Die Identifizierung spinnt mit P_NAME-Arrays
//
//--------------------------------------------------------------------------
varargs int id( string str, int lvl )
{
string plname;
if ( pl->QueryProp( P_GHOST ) )
if ( str == "geist" )
return 1;
else if ( ( sscanf( str, "geist von %s", plname ) == 1 ) &&
pl->id( plname ) )
return 1;
else if ( ( sscanf( str, "geist %s", plname ) == 1 ) &&
pl->id( plname ) )
return 1;
return pl->id( str, lvl );
}
//--------------------------------------------------------------------------
//
// long()
//
// Die Langbeschreibung im Spieler hadert mit dem Geschlecht NEUTER...
//
//--------------------------------------------------------------------------
varargs string long( /* void */ )
{
string slong;
slong = pl->long();
if ( _query_gender() == NEUTER )
{
string *along;
int i;
// alle Er-s und er-s suchen...
along = regexplode( slong, "\\<[Ee]r\\>" );
// ... und das r durch ein s ersetzen.
for ( i = 1 ; i < sizeof( along ) ; i += 2 )
along[ i ][ 1 ] = 's';
slong = implode( along, "" );
}
return slong;
}
//--------------------------------------------------------------------------
//
// short()
//
// Die Kurzbeschreibung im Spieler hat ein Problem mit P_NAME-Arrays
//
//--------------------------------------------------------------------------
string short( /* void */ )
{
mixed names;
string answer;
string title;
if ( pl->QueryProp( P_INVIS ) )
if ( interactive( previous_object() ) &&
IS_LEARNING( previous_object() ) )
return "(" + pl->Query( P_NAME ) + ") \n";
else
return (string)0;
names = _query_name_full();
if ( stringp( names ) )
names = ({ names, names, names, names });
if ( pl->QueryProp( P_GHOST ) )
answer = "Der Geist " + pl->QueryArticle( WESSEN, 0 ) + names[ WESSEN ];
else
answer = pl->QueryArticle( WER, 0 ) + names[ WER ];
if ( ( title = pl->QueryProp( P_TITLE ) ) &&
( title != "" ) )
answer += " " + title;
if ( !interactive( pl ) )
answer += " (netztot)";
return capitalize( answer ) + ".\n";
}
//--------------------------------------------------------------------------
//
// remove( Schnauze )
//
// aufräumen
//
//--------------------------------------------------------------------------
varargs int remove( int silent )
{
destruct( this_object() );
return 1;
}
//--------------------------------------------------------------------------
// -- ENDE --