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