blob: 3da5c9d1b8dd2304737c3fb863c491eab06785b1 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// container/restrictions.c -- container restrictions
4//
5// $Id: restrictions.c 9020 2015-01-10 21:49:41Z Zesstra $
6
7// This is a simple container to put objects in. It defines all functions
8// which are necessary to describe an object which can be filled with
9// other things.
10//
11// It will support restrictions for volume, weight etc.
12//
13// The following properties are defined:
14// P_MAX_WEIGHT - maximum weight which container can carry
15// P_TOTAL_WEIGHT - total weight, with contents.
16// P_WEIGHT - the weight of the container without contents
17//
18// Functions for manipulation of weight
19// MayAddWeight(weight) - Can <weight> be inserted?
20// AddWeight(weight) - Add an amount of <weight>
21//
22// IMPORTANT: unit equals 1 gram
23
24#pragma strict_types
25#pragma save_types
26//#pragma range_check
27#pragma no_clone
28#pragma pedantic
29
30#define NEED_PROTOTYPES
31
32#include "/sys/thing/properties.h"
33#include <properties.h>
34#include <defines.h>
35#include <thing/description.h>
36
37// local properties prototypes
38static int _query_total_weight();
39
40
41private nosave int LastWeightCalc, contents, LastObjectCount, objcount;
42private nosave int last_content_change;
43
44
45void create()
46{
47 Set( P_WEIGHT_PERCENT, 50 );
48 Set( P_TOTAL_WEIGHT, NOSETMETHOD, F_SET_METHOD );
49 Set( P_TOTAL_WEIGHT, PROTECTED, F_MODE );
50 Set( P_MAX_OBJECTS, 100 );
51 Set( P_TOTAL_OBJECTS, NOSETMETHOD, F_SET_METHOD );
52 Set( P_TOTAL_OBJECTS, PROTECTED, F_MODE );
53 LastWeightCalc = -1;
54 LastObjectCount = -1;
55}
56
57
58static int _query_last_content_change()
59{
60 return last_content_change;
61}
62
63
64// absichtlich public, da es von der simul_efun.c *direkt* aufgerufen
65// wird aus Performancegruenden!
66public varargs int _set_last_content_change( mixed wert )
67{
68 // Der uebergebene Wert ist unerheblich. Die Property
69 // P_LAST_CONTENT_CHANGE wird so oder so bei jedem SetProp()-
70 // Aufruf um eins erhoeht, um der 2s-"Unschaerfe" von time()
71 // aus dem Weg zu gehen.
72 return ++last_content_change;
73}
74
75
76int query_weight_contents()
77{
78 object *objs;
79 int w, w2, i;
80
81 if ( last_content_change == LastWeightCalc )
82 return contents;
83
84 w = 0;
85 objs = all_inventory(this_object());
86 i = sizeof(objs);
87
88 while ( i-- ){
89 if ( !(w2 = (int)objs[i]->QueryProp(P_TOTAL_WEIGHT)) )
90 w2 = (int)objs[i]->QueryProp(P_WEIGHT);
91 w += w2;
92 }
93
94 LastWeightCalc = last_content_change;
95 return contents = w;
96}
97
98
99static int _query_total_objects()
100{
101 if ( last_content_change == LastObjectCount )
102 return objcount;
103
104 objcount = sizeof( filter_objects( all_inventory(), "short" ) );
105 LastObjectCount = last_content_change;
106 return objcount;
107}
108
109
110// diese Funktion sollte von Raeumen natuerlich ueberschrieben werden...
111int MayAddObject( object ob )
112{
113 if (ob) {
114 if ( !ob->short() )
115 return 1; // invis-Objekte duerfen immer
116
117 if ( ob == ME || environment(ob) == ME)
118 return 1; // objekt ist schon drin
119 }
120
121 return (QueryProp(P_TOTAL_OBJECTS) < QueryProp(P_MAX_OBJECTS));
122}
123
124
125#define ENV environment
126#define PO previous_object()
127
128int MayAddWeight( int w )
129{
130 int nw, aw;
131
132 // was nix wiegt, passt
133 if ( w <= 0 )
134 return 0;
135
136 nw = w; // Gewicht im neuen Container
137 aw = 0; // Gewicht fuer das env()
138
139 // Von Raum in Behaelter im Spieler: Container sieht volles Gewicht (nw=w),
140 // Check im env() (Spieler) mit reduziertem Gewicht.
141 if ( ENV() && PO && ENV(PO) != ENV() )
142 aw = QueryProp(P_WEIGHT_PERCENT) * w / 100 || 1;
143
144 if ( PO && ENV(PO) && ENV(ENV(PO)) ){
145 // Wenn das Objekt ein env() hochbewegt wird, wird das Gewicht im alten
146 // Container abgezogen. Weiterer Check im env() ist unnoetig (aw=0).
147 if ( ENV(ENV(PO)) == ME )
148 nw = w - (int)ENV(PO)->QueryProp(P_WEIGHT_PERCENT) * w / 100;
149 // Eine Ebene tiefer bewegen: Test im neuen Container mit unveraendertem
150 // Gewicht; Check im env() mit um Gewichtsreduktion verringertem Gewicht
151 else if ( present( ME, ENV(PO) ) )
152 aw = QueryProp(P_WEIGHT_PERCENT) * w / 100 - w;
153 // Auf derselben Ebene verschieben (von Paket in Beutel):
154 // Neuer Container sieht volles Gewicht (nw=w), Check im env() mit
155 // Differenz aus Gewicht in Container1 und in Container2.
156 else if ( ENV(ENV(ENV(PO))) && ENV() == ENV(ENV(PO)) )
157 aw = QueryProp(P_WEIGHT_PERCENT) * w / 100
158 - ((int)ENV(PO)->QueryProp(P_WEIGHT_PERCENT) * w / 100 || 1);
159 }
160
161 if ( query_weight_contents() + nw > QueryProp(P_MAX_WEIGHT) )
162 // Container kann Gewicht nicht mehr aufnehmen
163 return -1;
164
165 if ( aw && ENV()->MayAddWeight(aw) < 0 )
166 // Umgebung des Containers kann Gewicht nicht mehr aufnehmen
167 return -2;
168
169 return 0;
170}
171
172
173/* Redefine PreventInsert() to prevent inserting of special objects. If
174 * a value greater 0 is returned the object ob can't be inserted in the
175 * container.
176 */
177public int PreventInsert( object ob ) { return 0; }
178public int PreventLeave( object ob, mixed dest ) { return 0; }
179public int PreventInsertLiving( object ob ) { return 0; }
180public int PreventLeaveLiving( object ob, mixed dest ) { return 0; }
181public void NotifyInsert(object ob, object oldenv) { }
182
183// **** local property methods
184static int _query_total_weight()
185{
186 return QueryProp(P_WEIGHT) +
187 (QueryProp(P_WEIGHT_PERCENT) * query_weight_contents() / 100);
188}
189
190
191// Hilfsfunktion
192static int _behalten( object ob, string uid )
193{
194 return (string)ob->QueryProp(P_KEEP_ON_SELL) == uid;
195}
196
197
198/*
199 *
200 * get a list of all contained objects matching a complex description
201 *
202 */
203
204#define POS_INVERS 0x01 /* nur zur funktionsinternen Verwendung */
205#define POS_LETZTES 0x02 /* nur zur funktionsinternen Verwendung */
206
207object *present_objects( string complex_desc )
208{
209 int i; // Zaehlervariable
210 int meth; // 0x01 = invers?, 0x02 = letztes?
211 object ob; // einzelnes temporaeres Objekt
212 object *obs; // liste der ausgewaehlten Objekte
213 object *erg; // zum sammeln bis es nachher zurueckgegeben wird...
214 string *strlst; // liste aller Gruppen die mit AND verknuepft sind
215 object haufen;
216
217 strlst = allocate(2);
218
219 if ( sscanf( complex_desc, "%s ausser %s", strlst[0], strlst[1]) == 2 ){
220 erg = present_objects( strlst[0] );
221 obs = present_objects( strlst[1] );
222 return erg-obs;
223 }
224
225 strlst = explode( complex_desc, " und " );
226 erg = ({});
227
228 for ( i = sizeof(strlst); i--; )
229 {
230 complex_desc = strlst[i];
231 // auf letzte/letztes/letzten pruefen...
232 if ( complex_desc[0..5] == "letzte" ){
233 switch( complex_desc[6..6] ){
234 case " ":
235 meth |= POS_LETZTES;
236 complex_desc = complex_desc[7..];
237 break;
238 case "s":
239 case "n":
240 case "m":
241 case "r":
242 if ( complex_desc[7..7] != " " )
243 break;
244 meth |= POS_LETZTES;
245 complex_desc = complex_desc[8..];
246 break;
247 default:
248 }
249 }
250
251 // auf verneinung pruefen
252 if ( complex_desc[0..5] == "nicht " ){
253 meth |= POS_INVERS;
254 complex_desc = complex_desc[6..];
255 }
256
257 obs=({});
258 // nun nach Main-Ids (Gruppen) suchen...
259 if ( meth & POS_LETZTES )
260 { // geht es nur um den letzten Gegenstand?
261 switch( complex_desc ){
262 case "waffe":
263 obs = filter_objects( all_inventory(), "QueryProp",
264 P_WEAPON_TYPE );
265 break;
266
267 case "ruestung":
268 obs = filter_objects( all_inventory(), "QueryProp",
269 P_ARMOUR_TYPE );
270 break;
271
272 case "kleidung":
273 obs = filter_objects( all_inventory(), "IsClothing");
274 break;
275
276 case "verschiedenem":
277 case "verschiedenes":
278 obs = all_inventory();
279 obs -= filter_objects( obs, "QueryProp", P_WEAPON_TYPE );
280 obs -= filter_objects( obs, "QueryProp", P_ARMOUR_TYPE );
281 obs -= filter_objects( obs, "IsClothing");
282 obs -= filter( obs, #'living/*'*/ );
283 break;
284
285 case "eigenes":
286 case "meins":
287 if (objectp(haufen=present("\nhaufen "+
288 this_player()->name(WEM)))) {
289 obs = all_inventory(haufen);
290 }
291 // kein break;, Fall-through!
292 case "behaltenem":
293 case "behaltenes":
294 obs += filter( all_inventory(), "_behalten", ME,
295 getuid(this_player() || previous_object()) );
296
297 obs += (QueryProp(P_ARMOURS) || ({}))
298 + ({ QueryProp(P_WEAPON) }) - ({ 0 });
299 break;
300
301 case "gegenstand":
302 obs = all_inventory() -
303 filter( all_inventory(), #'living/*'*/ );
304 break;
305
306 default:
307 obs = filter_objects( all_inventory(), "id", complex_desc );
308 }
309
310 // unsichtbare objekte entfernen
311 obs = filter_objects( obs, "short" );
312
313 // letzten Gegenstand raussuchen
314 obs = obs[0..0];
315 } // if (letzter Gegenstand)
316 else
317 { // ganze Gruppen und nicht nur das letzte Objekt
318 switch ( complex_desc )
319 {
320 case "allem":
321 case "alles":
322 case "jeden gegenstand":
323 case "jedem gegenstand":
324 case "gegenstaende":
325 case "alle gegenstaende":
326 case "allen gegenstaenden":
327 if ( meth & POS_INVERS )
328 continue; // alles nicht = nichts :)
329
330 obs = all_inventory() -
331 filter( all_inventory(), #'living/*'*/ );
332 break;
333
334 case "waffen":
335 case "jede waffe":
336 case "jeder waffe":
337 case "alle waffen":
338 case "allen waffen":
339 obs = filter_objects( all_inventory(), "QueryProp",
340 P_WEAPON_TYPE );
341 break;
342
343 case "ruestungen":
344 case "jede ruestung":
345 case "jeder ruestung":
346 case "alle ruestungen":
347 case "allen ruestungen":
348 obs = filter_objects( all_inventory(), "QueryProp",
349 P_ARMOUR_TYPE );
350 break;
351
352 case "kleidung":
353 case "jede kleidung":
354 case "jeder kleidung":
355 case "alle kleidung":
356 case "allen kleidung":
357 obs = filter_objects( all_inventory(), "IsClothing");
358 break;
359
360 case "gegenstand":
361 obs = filter_objects( all_inventory() -
362 filter( all_inventory(),
363 #'living/*'*/ ),
364 "short" )[0..0];
365 break;
366
367 case "verschiedenem":
368 case "verschiedenes":
369 obs = all_inventory();
370 obs -= filter_objects( obs, "QueryProp", P_WEAPON_TYPE );
371 obs -= filter_objects( obs, "QueryProp", P_ARMOUR_TYPE );
372 obs -= filter_objects( obs, "IsClothing");
373 obs -= filter( obs, #'living/*'*/ );
374 break;
375
376 case "eigenes":
377 case "eigenem":
378 case "eigenen":
379 case "meins":
380 case "alles eigene":
381 if (objectp(haufen=present("\nhaufen "+
382 this_player()->name(WEM)))) {
383 obs = all_inventory(haufen);
384 }
385 // kein break;, Fall-through!
386 case "behaltenem":
387 case "behaltenen":
388 case "behaltenes":
389 case "alles behaltene":
390 obs += filter( all_inventory(), "_behalten", ME,
391 getuid(this_player() || previous_object()) );
392
393 obs += (QueryProp(P_ARMOURS) || ({}))
394 + ({ QueryProp(P_WEAPON) }) - ({ 0 });
395 break;
396
397 default:
398 if ( complex_desc[0..3] == "jede" ||
399 complex_desc[0..4] == "alle ")
400 {
401 if ( complex_desc[4..4] == " " )
402 {
403 obs = filter_objects( all_inventory(), "id",
404 complex_desc[5..] );
405 break;
406 }
407 else
408 {
409 switch( complex_desc[4..5] )
410 {
411 case "m ":
412 case "r ":
413 case "n ":
414 case "s ":
415 obs = filter_objects( all_inventory(), "id",
416 complex_desc[6..] );
417 break;
418
419 default:
420 obs = 0;
421 }
422 if (obs)
423 break;
424 }
425 }
426
427 // Der Normalfall: einzelne ID...
428 ob = present( complex_desc, ME );
429 // Achtung: dieser Teil setzt das for() fort (continue) und
430 // umgeht dabei die Pruefung auf Sichtbarkeit nach dem Ende vom
431 // switch(). Aus diesem Grunde muss hier selber geprueft
432 // werden.
433 if ( meth & POS_INVERS )
434 {
435 if ( ob && ob != ME )
436 erg += (filter_objects( all_inventory(), "short" )
437 - ({ ob }) );
438 else
439 erg += filter_objects( all_inventory(), "short" );
440 }
441 else if ( ob && ob != ME && !ob->QueryProp(P_INVIS) )
442 erg += ({ ob }); //Normalfall: einzelne ID
443
444 continue;
445
446 } // switch
447 // unsichtbare objekte entfernen
448 obs = filter_objects( obs, "short" );
449 } // else
450
451 if ( meth & POS_INVERS )
452 erg += ( filter_objects( all_inventory(), "short" ) - obs );
453 else
454 erg += obs;
455 } // for
456 return erg;
457}
458
459/*
460 * returns a list of all found objects inside itself
461 * may call same function in objects inside
462 *
463 * Funktion wird nicht mehr von put_and_get aufgerufen, stattdessen wird
464 * direkt present_objects benutzt!
465 */
466object *locate_objects( string complex_desc, int info ) {
467 string was, wo;
468
469 if ( sscanf( complex_desc, "%s in %s", was, wo ) == 2 ){
470 object *found_obs = ({});
471 foreach(object invob: present_objects(wo)) {
472 // || ({}) weil invob ein Objekt ohne locate_objects() sein koennte.
473 found_obs += (object *)invob->locate_objects( was, info) || ({});
474 }
475 return found_obs;
476 }
477 // kein "in" gefunden
478 return present_objects( complex_desc );
479}
480