blob: 9536ef1b32d7a7ae8e5c9b49e17b0789a84885ed [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 {
37 printf("VSH: Prop %s, %O\n", k, v);
38 int reset_prop;
39 if (k[0] == VI_RESET_PREFIX)
40 {
41 reset_prop=1;
42 k=k[1..];
43 }
44 switch(k)
45 {
46 case P_READ_DETAILS:
47 if (reset_prop)
48 RemoveReadDetail(0);
49 else
50 SetProp(P_READ_DETAILS, ziel->QueryProp(P_READ_DETAILS));
51 walk_mapping(v, #'AddReadDetail);
52 break;
53 case P_DETAILS:
54 if (reset_prop)
55 RemoveDetail(0);
56 else
57 SetProp(P_DETAILS, ziel->QueryProp(P_DETAILS));
58 walk_mapping(v, #'AddDetail);
59 break;
60 case P_SMELLS:
61 if (reset_prop)
62 RemoveSmells(0);
63 else
64 SetProp(P_SMELLS, ziel->QueryProp(P_SMELLS));
65 walk_mapping(v, #'AddSmells);
66 break;
67 case P_SOUNDS:
68 if (reset_prop)
69 RemoveSounds(0);
70 else
71 SetProp(P_SOUNDS, ziel->QueryProp(P_SOUNDS));
72 walk_mapping(v, #'AddSounds);
73 break;
74 case P_TOUCH_DETAILS:
75 if (reset_prop)
76 RemoveTouchDetail(0);
77 else
78 SetProp(P_TOUCH_DETAILS, ziel->QueryProp(P_TOUCH_DETAILS));
79 walk_mapping(v, #'AddTouchDetail);
80 break;
81 case P_IDS:
82 if (reset_prop)
83 SetProp(P_IDS, v);
84 else
85 {
86 SetProp(P_IDS, ziel->QueryProp(P_IDS));
87 AddId(v);
88 }
89 case P_CLASS:
90 if (reset_prop)
91 SetProp(P_CLASS, v);
92 else
93 {
94 SetProp(P_CLASS, ziel->QueryProp(P_CLASS));
95 AddClass(v);
96 }
97 case P_ADJECTIVES:
98 if (reset_prop)
99 SetProp(P_ADJECTIVES, v);
100 else
101 {
102 SetProp(P_ADJECTIVES, ziel->QueryProp(P_ADJECTIVES));
103 AddAdjective(v);
104 }
105 break;
106
107 // Alle anderen Properties stumpf setzen.
108 default:
109 if (reset_prop)
110 SetProp(k, v);
111 else
112 {
113 mixed val = ziel->QueryProp(k);
114 // Arrays und Mapping koennen addiert werden, alles andere wird
115 // ueberschrieben.
116 if (pointerp(val) || mappingp(val))
117 SetProp(k, val + v);
118 else
119 SetProp(k, v);
120 }
121 } // switch
122 } // foreach
123}
124
125/*
126xcall
127/players/zesstra/vitem_shadow->set_shadow(find_object("/players/zesstra/seil#55513
1282"),([P_MATERIAL:([MAT_ICE:100]),P_SHORT:"Eis-Seil"]))
129*/
130public void set_shadow(object target, mapping p)
131{
132 // wenn schon beschattend, ists nen Fehler
133 if (query_shadowing(this_object()))
134 raise_error(sprintf("set_shadow(): Ein Objekt wird schon beschattet: "
135 "%O (Ziel jetzt: %O)\n",query_shadowing(this_object()), target));
136
137 // der Aufrufer muss eine eUID gleich meiner UID haben, damit er das
138 // Beschatten aktivieren kann. (Dieses Objekt hat immer die UID+eUID == eUID
139 // vom Cloner des Shadows, d.h. vom Erzeuger des vItems.) D.h. das
140 // Beschatten kann vom Erzeuger des vItems aktiviert werden.
141 if (getuid(this_object()) == geteuid(previous_object()))
142 {
143 configure_object(target, p);
144 if (shadow(target, 1) != target)
145 raise_error(sprintf("Kann %O nicht beschatten.\n",target));
146 }
147 else
148 raise_error(sprintf("Kann %O nicht beschatten, falsche eUID. "
149 "Meine: %s, Aufrufer: %s\n",
150 target, getuid(this_object()),
151 geteuid(previous_object()) ));
152}
153
154
155varargs int remove(int silent)
156{
157 // Sollten wir gerade etwas beschatten, ist der Aufruf von diesem remove()
158 // evtl. auch der vom Ziel. Wir machen das ganz einfach: Aufruf von remove()
159 // fuehrt zum Entsorgen von Ziel und diesem Objekt.
160 object ziel=query_shadowing(this_object());
161 // und ganz wichtig: nur wenn das Ziel noch ein virtuell anwesendes Items
162 // (vitem) ist, d.h. *kein* Environment hat.
163 if (ziel && !environment(ziel))
164 ziel->remove(1);
165
166 return ::remove(1);
167}
168
169// Dieses Objekt raeumt sich immer im ersten reset auf - es ist kurzlebig und
170// transient und Aenderungen an seinen Daten bleiben nicht erhalten.
171void reset()
172{
173 // BTW: Sollten wir gerade etwas beschatten, ist der Aufruf von diesem
174 // reset() evtl. auch der vom Ziel. (remove kuemmer sich drum)
175 remove(1);
176}
177
178// private ueberschreiben, damit es in diesem Objekt nicht gerufen werden kann
179// und im Beschatteten gerufen wird.
180private varargs void init(object origin)
181{
182}
183
184public varargs int move( object|string dest, int method )
185{
186 object ziel=query_shadowing(this_object());
187 int res;
188 if (ziel)
189 {
190 res=ziel->move(dest, method);
191 if (res == MOVE_OK)
192 {
Zesstrae5d86b12019-03-17 22:55:58 +0100193 // virtuellem environment bescheidsagen, dass das Objekt bewegt wurde.
194 cloner->VItemMoved(ziel);
Zesstra10e6d7d2018-11-28 22:36:57 +0100195 // und nach Bewegung des vitems ist das kein vitem mehr und der Schatten
196 // muss weg.
197 remove(1);
198 }
199 }
200 // Bewegen vom Schatten ist nicht. Und ohne Ziel braucht es den Schatten eh
201 // nicht.
202 else
203 {
204 remove(1);
205 res = ME_WAS_DESTRUCTED;
206 }
207 return res;
208}
209
210// Query und QueryProp liefern die abweichend hier definierten Properties,
211// oder ansonsten die aus dem beschatteten Objekt.
212public mixed QueryProp( string name )
213{
214 object ziel=query_shadowing(this_object());
215 if (ziel && !member(props,name))
216 {
217 return ziel->QueryProp(name);
218 }
219 return ::QueryProp(name);
220}
221
222public varargs mixed Query( string name, int Type )
223{
224 object ziel=query_shadowing(this_object());
225 if (ziel && !member(props,name))
226 {
227 return ziel->Query(name, Type);
228 }
229 return ::Query(name, Type);
230}
231
232public varargs mixed Set( string name, mixed Value, int Type, int extern )
233{
234 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
235 m_add(props,name);
236 return ::Set(name, Value, Type, extern_call());
237}
238
239public mixed SetProp( string name, mixed Value )
240{
241 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
242 m_add(props,name);
243 return ::SetProp(name, Value);
244}
245
246// Details hinzufuegen muss die passende Prop so markieren, dass sie aus
247// diesem Objekt geliefert wird.
248public void AddDetail(string|string* keys, string|string*|mapping|closure descr)
249{
250 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
251 m_add(props,P_DETAILS);
252 m_add(props,P_SPECIAL_DETAILS);
253 return ::AddDetail(keys, descr);
254}
255
256public void AddReadDetail(string|string* keys,
257 string|string*|mapping|closure descr )
258{
259 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
260 m_add(props,P_READ_DETAILS);
261 return ::AddDetail(keys, descr);
262}
263
264public void AddSounds(string|string* keys,
265 string|string*|mapping|closure descr )
266{
267 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
268 m_add(props,P_SOUNDS);
269 return ::AddDetail(keys, descr);
270}
271
272public void AddSmells(string|string* keys,
273 string|string*|mapping|closure descr )
274{
275 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
276 m_add(props,P_SMELLS);
277 return ::AddDetail(keys, descr);
278}
279
280public void AddTouchDetail(string|string* keys,
281 string|string*|mapping|closure descr )
282{
283 // Ab jetzt ist das unsere Prop, die aus dem Beschatteten ist egal.
284 m_add(props,P_TOUCH_DETAILS);
285 return ::AddDetail(keys, descr);
286}
287
288// Beides nicht unterstuetzt fuer vitems.
289visible void AddSpecialDetail(string|string* keys, string functionname )
290{
291 raise_error("Nicht unterstuetzt fuer vitem-shadows.\n");
292}
293visible void RemoveSpecialDetail(string|string* keys )
294{
295 raise_error("Nicht unterstuetzt fuer vitem-shadows.\n");
296}
297
298// Wird ggf. auf GetDetail im echten Item umgeleitet, damit jenes FP an
299// Details haben kann und man diese auch findet.
300public varargs string GetDetail(string key, string race, int sense)
301{
302 object ziel=query_shadowing(this_object());
303 if (!ziel)
304 return ::GetDetail(key, race, sense);
305
306 switch(sense)
307 {
308 case SENSE_SMELL: if (member(props, P_SMELLS))
309 return ::GetDetail(key, race, sense);
310 break;
311 case SENSE_SOUND: if (member(props, P_SOUNDS))
312 return ::GetDetail(key, race, sense);
313 break;
314 case SENSE_TOUCH: if (member(props, P_TOUCH_DETAILS))
315 return ::GetDetail(key, race, sense);
316 break;
317 case SENSE_READ: if (member(props, P_READ_DETAILS))
318 return ::GetDetail(key, race, sense);
319 break;
320
321 default: if (member(props, P_DETAILS))
322 return ::GetDetail(key, race, sense);
323 break;
324 }
325 // nix in diesem Objekt, GetDetail vom ziel darfs machen.
326 return ziel->GetDetail(key, race, sense);
327}
328
329// Sollen aus dem Beschatteten kommen
330public object *present_objects( string complex_desc )
331{
332 object ziel=query_shadowing(this_object());
333 if (ziel)
334 return ziel->present_objects(complex_desc);
335 return ::present_objects(complex_desc);
336}
337
338// Sollen aus dem Beschatteten kommen
339public object *locate_objects( string complex_desc, int info )
340{
341 object ziel=query_shadowing(this_object());
342 if (ziel)
343 return ziel->locate_objects(complex_desc, info);
344 return ::locate_objects(complex_desc, info);
345}
346
Zesstrabc517a42018-12-02 20:26:38 +0100347public object *AllVirtualEnvironments()
348{
349 if (cloner)
350 {
351 object *cloner_envs = all_environment(cloner)
352 || cloner->AllVirtualEnvironments();
353 if (cloner_envs)
354 return ({cloner}) + cloner_envs;
355 return ({cloner});
356 }
357 return 0;
358}
Zesstra10e6d7d2018-11-28 22:36:57 +0100359