blob: b5fe629393a1e05dda38941c16daf96f00c7772d [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 {
189 res=ziel->move(dest, method);
190 if (res == MOVE_OK)
191 {
Zesstrae5d86b12019-03-17 22:55:58 +0100192 // virtuellem environment bescheidsagen, dass das Objekt bewegt wurde.
193 cloner->VItemMoved(ziel);
Zesstra10e6d7d2018-11-28 22:36:57 +0100194 // und nach Bewegung des vitems ist das kein vitem mehr und der Schatten
195 // muss weg.
196 remove(1);
197 }
198 }
199 // Bewegen vom Schatten ist nicht. Und ohne Ziel braucht es den Schatten eh
200 // nicht.
201 else
202 {
203 remove(1);
204 res = ME_WAS_DESTRUCTED;
205 }
206 return res;
207}
208
209// Query und QueryProp liefern die abweichend hier definierten Properties,
210// oder ansonsten die aus dem beschatteten Objekt.
211public mixed QueryProp( string name )
212{
213 object ziel=query_shadowing(this_object());
214 if (ziel && !member(props,name))
215 {
216 return ziel->QueryProp(name);
217 }
218 return ::QueryProp(name);
219}
220
221public varargs mixed Query( string name, int Type )
222{
223 object ziel=query_shadowing(this_object());
224 if (ziel && !member(props,name))
225 {
226 return ziel->Query(name, Type);
227 }
228 return ::Query(name, Type);
229}
230
231public varargs mixed Set( string name, mixed Value, int Type, int extern )
232{
233 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
234 m_add(props,name);
235 return ::Set(name, Value, Type, extern_call());
236}
237
238public mixed SetProp( string name, mixed Value )
239{
240 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
241 m_add(props,name);
242 return ::SetProp(name, Value);
243}
244
245// Details hinzufuegen muss die passende Prop so markieren, dass sie aus
246// diesem Objekt geliefert wird.
247public void AddDetail(string|string* keys, string|string*|mapping|closure descr)
248{
249 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
250 m_add(props,P_DETAILS);
251 m_add(props,P_SPECIAL_DETAILS);
252 return ::AddDetail(keys, descr);
253}
254
255public void AddReadDetail(string|string* keys,
256 string|string*|mapping|closure descr )
257{
258 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
259 m_add(props,P_READ_DETAILS);
260 return ::AddDetail(keys, descr);
261}
262
263public void AddSounds(string|string* keys,
264 string|string*|mapping|closure descr )
265{
266 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
267 m_add(props,P_SOUNDS);
268 return ::AddDetail(keys, descr);
269}
270
271public void AddSmells(string|string* keys,
272 string|string*|mapping|closure descr )
273{
274 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
275 m_add(props,P_SMELLS);
276 return ::AddDetail(keys, descr);
277}
278
279public void AddTouchDetail(string|string* keys,
280 string|string*|mapping|closure descr )
281{
282 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
283 m_add(props,P_TOUCH_DETAILS);
284 return ::AddDetail(keys, descr);
285}
286
287// Beides nicht unterstuetzt fuer vitems.
288visible void AddSpecialDetail(string|string* keys, string functionname )
289{
290 raise_error("Nicht unterstuetzt fuer vitem-shadows.\n");
291}
292visible void RemoveSpecialDetail(string|string* keys )
293{
294 raise_error("Nicht unterstuetzt fuer vitem-shadows.\n");
295}
296
297// Wird ggf. auf GetDetail im echten Item umgeleitet, damit jenes FP an
298// Details haben kann und man diese auch findet.
299public varargs string GetDetail(string key, string race, int sense)
300{
301 object ziel=query_shadowing(this_object());
302 if (!ziel)
303 return ::GetDetail(key, race, sense);
304
305 switch(sense)
306 {
307 case SENSE_SMELL: if (member(props, P_SMELLS))
308 return ::GetDetail(key, race, sense);
309 break;
310 case SENSE_SOUND: if (member(props, P_SOUNDS))
311 return ::GetDetail(key, race, sense);
312 break;
313 case SENSE_TOUCH: if (member(props, P_TOUCH_DETAILS))
314 return ::GetDetail(key, race, sense);
315 break;
316 case SENSE_READ: if (member(props, P_READ_DETAILS))
317 return ::GetDetail(key, race, sense);
318 break;
319
320 default: if (member(props, P_DETAILS))
321 return ::GetDetail(key, race, sense);
322 break;
323 }
324 // nix in diesem Objekt, GetDetail vom ziel darfs machen.
325 return ziel->GetDetail(key, race, sense);
326}
327
328// Sollen aus dem Beschatteten kommen
329public object *present_objects( string complex_desc )
330{
331 object ziel=query_shadowing(this_object());
332 if (ziel)
333 return ziel->present_objects(complex_desc);
334 return ::present_objects(complex_desc);
335}
336
337// Sollen aus dem Beschatteten kommen
338public object *locate_objects( string complex_desc, int info )
339{
340 object ziel=query_shadowing(this_object());
341 if (ziel)
342 return ziel->locate_objects(complex_desc, info);
343 return ::locate_objects(complex_desc, info);
344}
345
Zesstrabc517a42018-12-02 20:26:38 +0100346public object *AllVirtualEnvironments()
347{
348 if (cloner)
349 {
350 object *cloner_envs = all_environment(cloner)
351 || cloner->AllVirtualEnvironments();
352 if (cloner_envs)
353 return ({cloner}) + cloner_envs;
354 return ({cloner});
355 }
356 return 0;
357}
Zesstra10e6d7d2018-11-28 22:36:57 +0100358