blob: 8bbaf177f81e13d64a2c31f31f2d242bd008a3a5 [file] [log] [blame]
Zesstra44030452018-11-12 22:34:02 +01001// MorgenGrauen MUDlib
2//
3// container/vitems.c -- managing virtually present automatic items
4//
Zesstra0d64cca2020-03-09 21:03:56 +01005#pragma strict_types,rtt_checks, range_check
Zesstra44030452018-11-12 22:34:02 +01006#pragma no_clone
7
8#include <properties.h>
9#define NEED_PROTOTYPES
10#include <thing/properties.h>
11#include <container/vitems.h>
12
13// Werte im Mapping in P_VITEMS:
14#define VI_PATH 0 // Pfad zur BP
15#define VI_REFRESH 1 // Refresheinstellung, s. AddItem
16#define VI_OBJECT 2 // Aktuelles Objekt des VItem
17#define VI_PROPS 3 // Props fuer das echte Objekt
18#define VI_SHADOW_PROPS 4 // Props fuer den shadow/vitem_proxy
19#define VI_LAST_OBJ 5 // letztes mitgenommenes Objekt
20#define VI_LENGTH 6
21
22// VI_REFRESH hat aehnliche Bedeutung wie bei AddItem, mit einer Besonderheit:
23// intern wird in Form eines negativen Wertes kodiert, ob das VItem gerade neu
24// erzeugt werden darf (negativ: ja, positiv: nein).
25
26/* Mehr zu VI_REFRESH:
27 * vitems raeumen sich ggf. selber weg. D.h. wenn der Clone des vitems nicht
28 * mehr ist, heisst das nicht, dass es jemand mitgenommen hat. In dem Fall
29 * muss es sofort (wenn seine Praesenz abgefragt wird) neu erzeugt werden.
30 * Die Logik ist wie folgt:
31 * Der Standardzustand von VI_REFRESH ist ein negierter Wert. Solange dies der
32 * Fall ist, wird ein vitem *immer* erzeugt, sofern es abgefragt wird, aber
33 * nicht da ist.
34 * Wird ein vitem hingegen bewegt/mitgenommen, wird VI_REFRESH auf den
35 * positiven Wert geaendert. In diesem Fall wird es NICHT mehr neu erzeugt,
36 * wenn es nicht als vitem praesent ist. Erst im naechsten reset() wird
37 * geprueft, ob es in Zukunft wieder neu erzeugt werden darf. Wenn ja, wird
38 * der Zahlenwert wieder negiert.
39 * Es ist Absicht, dass VI_REFRESH_ALWAYS auch nur maximal einmal pro reset()
40 * *mitgenommen* werden darf.
41 */
42
43
44//protected void create()
45//{
46//}
47
Zesstra7390fa92019-11-30 13:36:52 +010048protected void create_super() {
49 set_next_reset(-1);
50}
51
Zesstra44030452018-11-12 22:34:02 +010052public varargs void RemoveVItem(string key)
53{
54 mixed vitems=QueryProp(P_VITEMS);
55 if (mappingp(vitems) && member(vitems, key))
56 {
57 // Es wird auch zerstoert, wenn das genommene Objekt gerade im Raum
58 // rumliegt (weil Spieler es hat fallen lassen etc.)
59 if (vitems[key, VI_OBJECT])
bugfixd94d0932020-04-08 11:27:13 +020060 ({int})vitems[key, VI_OBJECT]->remove(1);
Zesstra44030452018-11-12 22:34:02 +010061 if (vitems[key, VI_LAST_OBJ]
62 && environment(vitems[key, VI_LAST_OBJ]) == this_object())
bugfixd94d0932020-04-08 11:27:13 +020063 ({int})vitems[key, VI_LAST_OBJ]->remove(1);
Zesstra44030452018-11-12 22:34:02 +010064
65 m_delete(vitems, key);
66 SetProp(P_VITEMS, vitems);
67 }
68}
69
70// TODO: braucht es dynamische refresh, shadowprops und props?
71public varargs void AddVItem(string key, int refresh, mapping shadowprops,
72 string path, mapping props)
73{
74 if (!sizeof(key))
75 return;
76 // Wenn path gegeben, muss es eine ladbare Blueprint sind
77 if (sizeof(path) && !load_object(path))
78 return;
79 if (!sizeof(path))
80 {
81 if (mappingp(props))
82 raise_error("Reine vitems erlauben keine <props>\n");
83 }
84
85 refresh ||= VI_REFRESH_NONE;
86 shadowprops ||= ([]);
87 // Wenn reines vItem und keine IDs gesetzt, wird <key> als ID verwendet,
88 // irgendwie muss es ja ansprechbar sein. (Wenn es ein Objekt mit Templat
89 // ist, hat es normalerweise die IDs aus dem Templat. Wenn man das nicht
90 // will, muss man es mit gezielter Angabe von P_IDS in den Shadowprops
Zesstraa724a842020-06-13 20:24:59 +020091 // ueberschreiben.) Gleiches fuer P_NAME (ohne ist ein "Ding")
Zesstra4a59a292020-06-18 22:42:43 +020092 // P_SHORT wird *nicht* automatisch gesetzt und sogar gezielt genullt. Ohne
93 // Kurzbeschreibung ist es zwar nicht wahrnehmbar, aber untersuchbar und der
94 // Zustand ist gar nicht selten gewuenscht fuer vitems.
Zesstra44030452018-11-12 22:34:02 +010095 if (!path)
96 {
97 if (!member(shadowprops, P_IDS))
98 shadowprops[P_IDS] = ({key});
99 if (!member(shadowprops, P_NAME))
100 shadowprops[P_NAME] = capitalize(key);
Zesstra4a59a292020-06-18 22:42:43 +0200101 if (!member(shadowprops, P_SHORT))
102 shadowprops[P_SHORT] = 0;
Zesstra44030452018-11-12 22:34:02 +0100103 }
104 mixed vitems=QueryProp(P_VITEMS);
105 if (!mappingp(vitems))
106 vitems = m_allocate(1, VI_LENGTH);
107 vitems[key, VI_PATH] = path;
108 vitems[key, VI_REFRESH] = negate(refresh);
109 vitems[key, VI_PROPS] = props;
110 vitems[key, VI_SHADOW_PROPS] = shadowprops;
111 SetProp(P_VITEMS, vitems);
112}
113
114
115private void configure_object(object ob, mapping props)
116{
117 foreach (string k, mixed v : props)
118 {
119 int reset_prop;
120 if (k[0] == VI_RESET_PREFIX)
121 {
122 reset_prop=1;
123 k=k[1..];
124 }
125 switch(k)
126 {
127 case P_READ_DETAILS:
bugfixd94d0932020-04-08 11:27:13 +0200128 if (reset_prop) ({void})ob->RemoveReadDetail(0);
Zesstra44030452018-11-12 22:34:02 +0100129 walk_mapping(v, "AddReadDetail", ob);
130 break;
131 case P_DETAILS:
bugfixd94d0932020-04-08 11:27:13 +0200132 if (reset_prop) ({void})ob->RemoveDetail(0);
Zesstra44030452018-11-12 22:34:02 +0100133 walk_mapping(v, "AddDetail", ob);
134 break;
135 case P_SMELLS:
bugfixd94d0932020-04-08 11:27:13 +0200136 if (reset_prop) ({void})ob->RemoveSmells(0);
Zesstra44030452018-11-12 22:34:02 +0100137 walk_mapping(v, "AddSmells", ob);
138 break;
139 case P_SOUNDS:
bugfixd94d0932020-04-08 11:27:13 +0200140 if (reset_prop) ({void})ob->RemoveSounds(0);
Zesstra44030452018-11-12 22:34:02 +0100141 walk_mapping(v, "AddSounds", ob);
142 break;
143 case P_TOUCH_DETAILS:
bugfixd94d0932020-04-08 11:27:13 +0200144 if (reset_prop) ({void})ob->RemoveTouchDetail(0);
Zesstra44030452018-11-12 22:34:02 +0100145 walk_mapping(v, "AddTouchDetail", ob);
146 break;
147 case P_IDS:
bugfixd94d0932020-04-08 11:27:13 +0200148 if (reset_prop) ({string*})ob->SetProp(P_IDS, v);
149 else ({void})ob->AddId(v);
Zesstra44030452018-11-12 22:34:02 +0100150 case P_CLASS:
bugfixd94d0932020-04-08 11:27:13 +0200151 if (reset_prop) ({string*})ob->SetProp(P_CLASS, v);
152 else ({void})ob->AddClass(v);
Zesstra44030452018-11-12 22:34:02 +0100153 case P_ADJECTIVES:
bugfixd94d0932020-04-08 11:27:13 +0200154 if (reset_prop) ({string*})ob->SetProp(P_ADJECTIVES, v);
155 else ({void})ob->AddAdjective(v);
Zesstra44030452018-11-12 22:34:02 +0100156 break;
157
158 // Alle anderen Properties stumpf setzen.
159 default:
bugfixd94d0932020-04-08 11:27:13 +0200160 ({mixed})ob->SetProp(k, v);
Zesstra44030452018-11-12 22:34:02 +0100161 }
162 }
163}
164
165// Clont ein vitem, falls noetig.
166// Nebeneffekt ist aber in jedem Fall auch, dass ein nicht mehr virtuell
167// anwesendes Objekt als VI_LAST_OBJ gespeichert und VI_OBJECT geloescht wird.
168private void check_vitem(string key, string path, int refresh,
169 object obj, mapping props, mapping shadow_props,
170 object last_obj)
171{
172 // Ist es noch da? Ein vItem ist "da", wenn obj auf ein gueltiges Objekt
173 // zeigt, welches *KEIN* Environment hat. (Hat es ein Environment, wurde es
174 // mitgenommen.)
175 if (obj)
176 {
177 if (!environment(obj))
178 return;
179 // wenn es mitgenommen wurde, ist obj in jedem Fall kein vItem mehr:
180 // (eigentlich wird das in VItemMoved schon gemacht, aber mal fuer den
181 // Fall, dass jemand den Shadow hart entsorgt hat o.ae.)
182 last_obj = obj;
183 obj = 0;
184 // und wird ggf. unten neu erzeugt.
185 }
186
187 if (refresh < 0)
188 {
189 object sh;
190 if (path)
191 {
192 obj=clone_object(path);
bugfixd94d0932020-04-08 11:27:13 +0200193 ({int})obj->SetAutoObject(1);
Zesstra44030452018-11-12 22:34:02 +0100194 if (mappingp(props))
195 configure_object(obj, props);
196 // Schatten erzeugen, welcher die Beschreibung des Objekts im Container nach
197 // den Props in shadow_props abaendert.
198 sh = clone_object("/obj/vitem_shadow");
bugfixd94d0932020-04-08 11:27:13 +0200199 ({void})sh->set_shadow(obj, shadow_props);
Zesstra44030452018-11-12 22:34:02 +0100200 }
201 else
202 {
203 obj=clone_object("/obj/vitem_proxy");
204 configure_object(obj, shadow_props);
205 // no shadow needed in this case.
206 }
207 }
208}
209
210// Erzeugt Instanzen der vItems (sofern noetig und erlaubt durch
211// Refresh-Parameter).
212private mixed CheckVItems()
213{
214 mixed vitems=QueryProp(P_VITEMS);
215 if (!mappingp(vitems))
216 vitems = m_allocate(0, VI_LENGTH);
217 walk_mapping(vitems, #'check_vitem);
218 return vitems;
219}
220
221// Liefert alle in diesem Raum virtuell anwesenden Items
222public object *GetVItemClones()
223{
224 mapping vitems = CheckVItems();
225 return filter(m_values(vitems, VI_OBJECT), #'objectp);
226}
227
228public object present_vitem(string complex_desc)
229{
230 foreach(object o : GetVItemClones())
231 {
bugfixd94d0932020-04-08 11:27:13 +0200232 if (({int})o->id(complex_desc))
Zesstra44030452018-11-12 22:34:02 +0100233 return o;
234 }
235 return 0;
236}
237
238// wird aus dem Shadow fuer das VItem gerufen, wenn es genomment etc. wird.
239// In dem Fall wird das Refresh "gesperrt", d.h. es wird fruehestens nach dem
240// naechsten Reset wieder neu erzeugt - sofern im naechsten Reset die
241// Vorraussetzungen erfuellt sind.
242public void VItemMoved(object ob)
243{
244 if (load_name(previous_object()) == "/obj/vitem_shadow")
245 {
246 mapping vitems = QueryProp(P_VITEMS);
247 if (!mappingp(vitems))
248 return;
249 // passendes vitem suchen
250 foreach(string key, string path, int refresh, object o, mapping props,
251 mapping shadow_props, object last_obj: &vitems)
252 {
253 if (ob != o)
254 continue;
255 else
256 {
257 // mitgenommenes Objekt merken und vitem-objekt loeschen
258 last_obj = o;
259 o = 0;
260 // Sperren gegen sofortiges Neuerzeugen, wenn refresh nicht
261 // VI_REFRESH_INSTANT ist.
262 if (refresh != VI_REFRESH_INSTANT)
263 refresh = negate(refresh);
264 break;
265 }
266 }
267 }
268}
269
270void reset()
271{
272 mapping vitems=QueryProp(P_VITEMS);
273 if (!mappingp(vitems))
274 return;
275 foreach(string key, string path, int refresh, object obj,
276 mapping props, mapping shadow_props, object last_obj : &vitems)
277 {
278 // Wenn negativ (d.h. vItem wurde noch nicht mitgenommen), 0 oder
279 // REFRESH_NONE, muss hier nix gemacht werden.
280 if (refresh <= REFRESH_NONE)
281 continue;
282
283 // Wenn last_obj nicht mehr existiert, darf (ausgenommen natuerlich
284 // REFFRESH_NONE) immer neu erzeugt werden.
285 if (!last_obj)
286 {
287 refresh=negate(refresh);
288 continue;
289 }
290
291 // restliche Faelle
292 switch(refresh)
293 {
294 case VI_REFRESH_MOVE_HOME:
295 // Wenn das Objekt nicht mehr als vItem hier ist (auch wenn es hier im
296 // Raum liegt!), wird es heim bewegt (sprich: zerstoert und neues
297 // vitem).
298 // (Da man hier nur hinkommt, wenn es mitgenommen wurde (refresh > 0),
299 // wird es immer refresht...
300 // Zu beachten: es soll auch nicht hier in diesem Container rumliegen
301 // nach dem Heimbewegen, also zerstoeren!
bugfixd94d0932020-04-08 11:27:13 +0200302 ({int})last_obj->remove(1);
Zesstra44030452018-11-12 22:34:02 +0100303 // Fallthrough
304 case VI_REFRESH_REMOVE:
305 // wenn nicht mehr als vItem hier ist (d.h. auch wenn es hier im Raum
306 // rumliegt!) darf es neu erzeugt werden.
307 // (Hierher kommt die Ausfuehrung nur her, wenn es mitgenommen
308 // wurde, d.h. letztendlich: immer. d.h. Fallthrough.)
309 case VI_REFRESH_ALWAYS:
310 // neu erzeugen
311 refresh=negate(refresh);
312 break;
313 }
314 }
315}
316