blob: 7d8e4cd2e7bedcd67cbb74c79c7d8db09049903f [file] [log] [blame]
Zesstra10e6d7d2018-11-28 22:36:57 +01001#pragma strong_types,rtt_checks
2
3#include <moving.h>
4#include <properties.h>
5#include <container/vitems.h>
6
7// Einschraenkungen: Alle _query_* Querymethoden und _set_* Setmethoden im
8// Ziel werden nicht beschattet.
9
10
11// Alle nicht explizit zum oeffentlichen Interface von /std/container
12// gehoerenden (d.h. alle nicht explizit "public" definierten) Funktionen
13// werden protected geerbt. Damit koennen sie von aussen nicht gerufen werden
14// und der Effekt ist, dass sie nicht im Shadow gerufen werden, sondern im
15// beschatteten Objekt.
16protected functions nosave private variables inherit "/std/container";
17
18// Mapping ohne Values. Keys zeigen an, welche Props dieses Objekt im
19// Zielobjekt beschattet.
20mapping props;
21
Zesstrabc517a42018-12-02 20:26:38 +010022object cloner;
Zesstra10e6d7d2018-11-28 22:36:57 +010023
24protected void create()
25{
Zesstrabc517a42018-12-02 20:26:38 +010026 cloner=previous_object();
Zesstra10e6d7d2018-11-28 22:36:57 +010027 set_next_reset(7200);
28}
29
30// Einige spezielle Props (wie Details etc. und Props mit Arrays oder
31// Mappings) werden gemerged mit dem Ziel, alle anderen ueberschrieben.
32private void configure_object(object ziel, mapping newprops)
33{
34 props = ([:0]);
35 foreach (string k, mixed v : newprops)
36 {
Zesstra10e6d7d2018-11-28 22:36:57 +010037 int reset_prop;
38 if (k[0] == VI_RESET_PREFIX)
39 {
40 reset_prop=1;
41 k=k[1..];
42 }
43 switch(k)
44 {
45 case P_READ_DETAILS:
46 if (reset_prop)
47 RemoveReadDetail(0);
48 else
49 SetProp(P_READ_DETAILS, ziel->QueryProp(P_READ_DETAILS));
50 walk_mapping(v, #'AddReadDetail);
51 break;
52 case P_DETAILS:
53 if (reset_prop)
54 RemoveDetail(0);
55 else
56 SetProp(P_DETAILS, ziel->QueryProp(P_DETAILS));
57 walk_mapping(v, #'AddDetail);
58 break;
59 case P_SMELLS:
60 if (reset_prop)
61 RemoveSmells(0);
62 else
63 SetProp(P_SMELLS, ziel->QueryProp(P_SMELLS));
64 walk_mapping(v, #'AddSmells);
65 break;
66 case P_SOUNDS:
67 if (reset_prop)
68 RemoveSounds(0);
69 else
70 SetProp(P_SOUNDS, ziel->QueryProp(P_SOUNDS));
71 walk_mapping(v, #'AddSounds);
72 break;
73 case P_TOUCH_DETAILS:
74 if (reset_prop)
75 RemoveTouchDetail(0);
76 else
77 SetProp(P_TOUCH_DETAILS, ziel->QueryProp(P_TOUCH_DETAILS));
78 walk_mapping(v, #'AddTouchDetail);
79 break;
80 case P_IDS:
81 if (reset_prop)
82 SetProp(P_IDS, v);
83 else
84 {
85 SetProp(P_IDS, ziel->QueryProp(P_IDS));
86 AddId(v);
87 }
88 case P_CLASS:
89 if (reset_prop)
90 SetProp(P_CLASS, v);
91 else
92 {
93 SetProp(P_CLASS, ziel->QueryProp(P_CLASS));
94 AddClass(v);
95 }
96 case P_ADJECTIVES:
97 if (reset_prop)
98 SetProp(P_ADJECTIVES, v);
99 else
100 {
101 SetProp(P_ADJECTIVES, ziel->QueryProp(P_ADJECTIVES));
102 AddAdjective(v);
103 }
104 break;
105
106 // Alle anderen Properties stumpf setzen.
107 default:
108 if (reset_prop)
109 SetProp(k, v);
110 else
111 {
112 mixed val = ziel->QueryProp(k);
113 // Arrays und Mapping koennen addiert werden, alles andere wird
114 // ueberschrieben.
115 if (pointerp(val) || mappingp(val))
116 SetProp(k, val + v);
117 else
118 SetProp(k, v);
119 }
120 } // switch
121 } // foreach
122}
123
124/*
125xcall
126/players/zesstra/vitem_shadow->set_shadow(find_object("/players/zesstra/seil#55513
1272"),([P_MATERIAL:([MAT_ICE:100]),P_SHORT:"Eis-Seil"]))
128*/
129public void set_shadow(object target, mapping p)
130{
131 // wenn schon beschattend, ists nen Fehler
132 if (query_shadowing(this_object()))
133 raise_error(sprintf("set_shadow(): Ein Objekt wird schon beschattet: "
134 "%O (Ziel jetzt: %O)\n",query_shadowing(this_object()), target));
135
136 // der Aufrufer muss eine eUID gleich meiner UID haben, damit er das
137 // Beschatten aktivieren kann. (Dieses Objekt hat immer die UID+eUID == eUID
138 // vom Cloner des Shadows, d.h. vom Erzeuger des vItems.) D.h. das
139 // Beschatten kann vom Erzeuger des vItems aktiviert werden.
140 if (getuid(this_object()) == geteuid(previous_object()))
141 {
142 configure_object(target, p);
143 if (shadow(target, 1) != target)
144 raise_error(sprintf("Kann %O nicht beschatten.\n",target));
145 }
146 else
147 raise_error(sprintf("Kann %O nicht beschatten, falsche eUID. "
148 "Meine: %s, Aufrufer: %s\n",
149 target, getuid(this_object()),
150 geteuid(previous_object()) ));
151}
152
153
154varargs int remove(int silent)
155{
156 // Sollten wir gerade etwas beschatten, ist der Aufruf von diesem remove()
157 // evtl. auch der vom Ziel. Wir machen das ganz einfach: Aufruf von remove()
158 // fuehrt zum Entsorgen von Ziel und diesem Objekt.
159 object ziel=query_shadowing(this_object());
160 // und ganz wichtig: nur wenn das Ziel noch ein virtuell anwesendes Items
161 // (vitem) ist, d.h. *kein* Environment hat.
162 if (ziel && !environment(ziel))
163 ziel->remove(1);
164
165 return ::remove(1);
166}
167
168// Dieses Objekt raeumt sich immer im ersten reset auf - es ist kurzlebig und
169// transient und Aenderungen an seinen Daten bleiben nicht erhalten.
170void reset()
171{
172 // BTW: Sollten wir gerade etwas beschatten, ist der Aufruf von diesem
173 // reset() evtl. auch der vom Ziel. (remove kuemmer sich drum)
174 remove(1);
175}
176
177// private ueberschreiben, damit es in diesem Objekt nicht gerufen werden kann
178// und im Beschatteten gerufen wird.
179private varargs void init(object origin)
180{
181}
182
183public varargs int move( object|string dest, int method )
184{
185 object ziel=query_shadowing(this_object());
186 int res;
187 if (ziel)
188 {
Zesstra6959b662020-03-29 19:33:04 +0200189 // PreventMove() im Ziel fragt die Props P_NOGET, P_WEIGHT etc. nicht via
190 // Callother ab, daher wird die Abfrage nicht durch diesen Shadow
191 // geleitet. Daher muss hier selber geprueft werden. Das PreventMove() in
192 // diesem Objekt beruecksichtigt die Properties des Schatten und des
193 // Beschatteten.
194 // Bemerkung: das bedeutet, dass PreventInsert() auch zweimal gerufen
195 // wird, fuer den Shadow und das Ziel. Deswegen darf man auch *nicht* per
196 // M_NOCHECK bewegen, weil die PreventInsert() fuer den Beschatteten ja
197 // noch ablehnend sein koennen.
198 dest = move_norm_dest(dest);
199 res = PreventMove(dest, 0, method);
200 if (res)
201 {
202 // auf gueltigen Fehler pruefen, wer weiss, was Magier da evtl.
203 // versehentlich zurueckgeben.
204 if (VALID_MOVE_ERROR(res))
205 return res;
206 else
207 return ME_DONT_WANT_TO_BE_MOVED;
208 }
209 res = ziel->move(dest, method);
Zesstra10e6d7d2018-11-28 22:36:57 +0100210 if (res == MOVE_OK)
211 {
Zesstrae5d86b12019-03-17 22:55:58 +0100212 // virtuellem environment bescheidsagen, dass das Objekt bewegt wurde.
213 cloner->VItemMoved(ziel);
Zesstra10e6d7d2018-11-28 22:36:57 +0100214 // und nach Bewegung des vitems ist das kein vitem mehr und der Schatten
215 // muss weg.
216 remove(1);
217 }
218 }
219 // Bewegen vom Schatten ist nicht. Und ohne Ziel braucht es den Schatten eh
220 // nicht.
221 else
222 {
223 remove(1);
224 res = ME_WAS_DESTRUCTED;
225 }
226 return res;
227}
228
229// Query und QueryProp liefern die abweichend hier definierten Properties,
230// oder ansonsten die aus dem beschatteten Objekt.
231public mixed QueryProp( string name )
232{
233 object ziel=query_shadowing(this_object());
234 if (ziel && !member(props,name))
235 {
236 return ziel->QueryProp(name);
237 }
238 return ::QueryProp(name);
239}
240
241public varargs mixed Query( string name, int Type )
242{
243 object ziel=query_shadowing(this_object());
244 if (ziel && !member(props,name))
245 {
246 return ziel->Query(name, Type);
247 }
248 return ::Query(name, Type);
249}
250
251public varargs mixed Set( string name, mixed Value, int Type, int extern )
252{
253 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
254 m_add(props,name);
255 return ::Set(name, Value, Type, extern_call());
256}
257
258public mixed SetProp( string name, mixed Value )
259{
260 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
261 m_add(props,name);
262 return ::SetProp(name, Value);
263}
264
265// Details hinzufuegen muss die passende Prop so markieren, dass sie aus
266// diesem Objekt geliefert wird.
267public void AddDetail(string|string* keys, string|string*|mapping|closure descr)
268{
269 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
270 m_add(props,P_DETAILS);
271 m_add(props,P_SPECIAL_DETAILS);
272 return ::AddDetail(keys, descr);
273}
274
275public void AddReadDetail(string|string* keys,
276 string|string*|mapping|closure descr )
277{
278 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
279 m_add(props,P_READ_DETAILS);
Zesstrad577e4f2020-01-15 22:56:49 +0100280 return ::AddReadDetail(keys, descr);
Zesstra10e6d7d2018-11-28 22:36:57 +0100281}
282
283public void AddSounds(string|string* keys,
284 string|string*|mapping|closure descr )
285{
286 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
287 m_add(props,P_SOUNDS);
Zesstrad577e4f2020-01-15 22:56:49 +0100288 return ::AddSounds(keys, descr);
Zesstra10e6d7d2018-11-28 22:36:57 +0100289}
290
291public void AddSmells(string|string* keys,
292 string|string*|mapping|closure descr )
293{
294 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
295 m_add(props,P_SMELLS);
Zesstrad577e4f2020-01-15 22:56:49 +0100296 return ::AddSmells(keys, descr);
Zesstra10e6d7d2018-11-28 22:36:57 +0100297}
298
299public void AddTouchDetail(string|string* keys,
300 string|string*|mapping|closure descr )
301{
302 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
303 m_add(props,P_TOUCH_DETAILS);
Zesstrad577e4f2020-01-15 22:56:49 +0100304 return ::AddTouchDetail(keys, descr);
Zesstra10e6d7d2018-11-28 22:36:57 +0100305}
306
307// Beides nicht unterstuetzt fuer vitems.
308visible void AddSpecialDetail(string|string* keys, string functionname )
309{
310 raise_error("Nicht unterstuetzt fuer vitem-shadows.\n");
311}
312visible void RemoveSpecialDetail(string|string* keys )
313{
314 raise_error("Nicht unterstuetzt fuer vitem-shadows.\n");
315}
316
317// Wird ggf. auf GetDetail im echten Item umgeleitet, damit jenes FP an
318// Details haben kann und man diese auch findet.
319public varargs string GetDetail(string key, string race, int sense)
320{
321 object ziel=query_shadowing(this_object());
322 if (!ziel)
323 return ::GetDetail(key, race, sense);
324
325 switch(sense)
326 {
327 case SENSE_SMELL: if (member(props, P_SMELLS))
328 return ::GetDetail(key, race, sense);
329 break;
330 case SENSE_SOUND: if (member(props, P_SOUNDS))
331 return ::GetDetail(key, race, sense);
332 break;
333 case SENSE_TOUCH: if (member(props, P_TOUCH_DETAILS))
334 return ::GetDetail(key, race, sense);
335 break;
336 case SENSE_READ: if (member(props, P_READ_DETAILS))
337 return ::GetDetail(key, race, sense);
338 break;
339
340 default: if (member(props, P_DETAILS))
341 return ::GetDetail(key, race, sense);
342 break;
343 }
344 // nix in diesem Objekt, GetDetail vom ziel darfs machen.
345 return ziel->GetDetail(key, race, sense);
346}
347
348// Sollen aus dem Beschatteten kommen
349public object *present_objects( string complex_desc )
350{
351 object ziel=query_shadowing(this_object());
352 if (ziel)
353 return ziel->present_objects(complex_desc);
354 return ::present_objects(complex_desc);
355}
356
357// Sollen aus dem Beschatteten kommen
358public object *locate_objects( string complex_desc, int info )
359{
360 object ziel=query_shadowing(this_object());
361 if (ziel)
362 return ziel->locate_objects(complex_desc, info);
363 return ::locate_objects(complex_desc, info);
364}
365
Zesstrabc517a42018-12-02 20:26:38 +0100366public object *AllVirtualEnvironments()
367{
368 if (cloner)
369 {
370 object *cloner_envs = all_environment(cloner)
371 || cloner->AllVirtualEnvironments();
372 if (cloner_envs)
373 return ({cloner}) + cloner_envs;
374 return ({cloner});
375 }
376 return 0;
377}
Zesstra10e6d7d2018-11-28 22:36:57 +0100378