blob: 30b8df1c726bdf0fad59b9e8dca2beed5099f39f [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
MG Mud User88f12472016-06-24 23:31:02 +020028
29#define NEED_PROTOTYPES
30
31#include "/sys/thing/properties.h"
32#include <properties.h>
33#include <defines.h>
34#include <thing/description.h>
Zesstracc377ca2018-11-12 23:08:01 +010035#include <container/vitems.h>
MG Mud User88f12472016-06-24 23:31:02 +020036
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
Zesstra52d40932018-11-28 22:05:15 +010045protected void create()
MG Mud User88f12472016-06-24 23:31:02 +020046{
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-- ){
Zesstra231c3aa2020-03-08 12:43:20 +010089 if ( !(w2 = ({int})objs[i]->QueryProp(P_TOTAL_WEIGHT)) )
90 w2 = ({int})objs[i]->QueryProp(P_WEIGHT);
MG Mud User88f12472016-06-24 23:31:02 +020091 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...
Zesstra52d40932018-11-28 22:05:15 +0100111public int MayAddObject( object ob )
MG Mud User88f12472016-06-24 23:31:02 +0200112{
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
Zesstra52d40932018-11-28 22:05:15 +0100128public int MayAddWeight( int w )
MG Mud User88f12472016-06-24 23:31:02 +0200129{
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 )
Zesstra231c3aa2020-03-08 12:43:20 +0100148 nw = w - ({int})ENV(PO)->QueryProp(P_WEIGHT_PERCENT) * w / 100;
MG Mud User88f12472016-06-24 23:31:02 +0200149 // 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
Zesstra231c3aa2020-03-08 12:43:20 +0100158 - (({int})ENV(PO)->QueryProp(P_WEIGHT_PERCENT) * w / 100 || 1);
MG Mud User88f12472016-06-24 23:31:02 +0200159 }
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) { }
Bugfixa5f76da2017-02-16 22:55:33 +0100182public void NotifyLeave(object ob, object dest) { }
MG Mud User88f12472016-06-24 23:31:02 +0200183
184// **** local property methods
185static int _query_total_weight()
186{
187 return QueryProp(P_WEIGHT) +
188 (QueryProp(P_WEIGHT_PERCENT) * query_weight_contents() / 100);
189}
190
191
192// Hilfsfunktion
193static int _behalten( object ob, string uid )
194{
Zesstra231c3aa2020-03-08 12:43:20 +0100195 return ({string})ob->QueryProp(P_KEEP_ON_SELL) == uid;
MG Mud User88f12472016-06-24 23:31:02 +0200196}
197
198
199/*
200 *
201 * get a list of all contained objects matching a complex description
202 *
203 */
204
205#define POS_INVERS 0x01 /* nur zur funktionsinternen Verwendung */
206#define POS_LETZTES 0x02 /* nur zur funktionsinternen Verwendung */
207
Zesstra52d40932018-11-28 22:05:15 +0100208public object *present_objects( string complex_desc )
MG Mud User88f12472016-06-24 23:31:02 +0200209{
210 int i; // Zaehlervariable
211 int meth; // 0x01 = invers?, 0x02 = letztes?
212 object ob; // einzelnes temporaeres Objekt
213 object *obs; // liste der ausgewaehlten Objekte
214 object *erg; // zum sammeln bis es nachher zurueckgegeben wird...
215 string *strlst; // liste aller Gruppen die mit AND verknuepft sind
216 object haufen;
217
218 strlst = allocate(2);
219
220 if ( sscanf( complex_desc, "%s ausser %s", strlst[0], strlst[1]) == 2 ){
221 erg = present_objects( strlst[0] );
222 obs = present_objects( strlst[1] );
223 return erg-obs;
224 }
225
226 strlst = explode( complex_desc, " und " );
227 erg = ({});
228
229 for ( i = sizeof(strlst); i--; )
230 {
231 complex_desc = strlst[i];
232 // auf letzte/letztes/letzten pruefen...
233 if ( complex_desc[0..5] == "letzte" ){
234 switch( complex_desc[6..6] ){
235 case " ":
236 meth |= POS_LETZTES;
237 complex_desc = complex_desc[7..];
238 break;
239 case "s":
240 case "n":
241 case "m":
242 case "r":
243 if ( complex_desc[7..7] != " " )
244 break;
245 meth |= POS_LETZTES;
246 complex_desc = complex_desc[8..];
247 break;
248 default:
249 }
250 }
251
252 // auf verneinung pruefen
253 if ( complex_desc[0..5] == "nicht " ){
254 meth |= POS_INVERS;
255 complex_desc = complex_desc[6..];
256 }
257
Zesstracc377ca2018-11-12 23:08:01 +0100258 obs = ({});
259 // all_inventory() und VItems (virtuell anwesende Items)
260 // zusammensammeln:
261 object *my_inventory = all_inventory() + GetVItemClones();
262
MG Mud User88f12472016-06-24 23:31:02 +0200263 // nun nach Main-Ids (Gruppen) suchen...
264 if ( meth & POS_LETZTES )
265 { // geht es nur um den letzten Gegenstand?
266 switch( complex_desc ){
267 case "waffe":
Zesstracc377ca2018-11-12 23:08:01 +0100268 obs = filter_objects( my_inventory, "QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +0200269 P_WEAPON_TYPE );
270 break;
271
272 case "ruestung":
Zesstracc377ca2018-11-12 23:08:01 +0100273 obs = filter_objects( my_inventory, "QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +0200274 P_ARMOUR_TYPE );
275 break;
276
277 case "kleidung":
Zesstracc377ca2018-11-12 23:08:01 +0100278 obs = filter_objects( my_inventory, "IsClothing");
MG Mud User88f12472016-06-24 23:31:02 +0200279 break;
280
281 case "verschiedenem":
282 case "verschiedenes":
Zesstracc377ca2018-11-12 23:08:01 +0100283 obs = my_inventory;
MG Mud User88f12472016-06-24 23:31:02 +0200284 obs -= filter_objects( obs, "QueryProp", P_WEAPON_TYPE );
285 obs -= filter_objects( obs, "QueryProp", P_ARMOUR_TYPE );
286 obs -= filter_objects( obs, "IsClothing");
287 obs -= filter( obs, #'living/*'*/ );
288 break;
289
290 case "eigenes":
291 case "meins":
292 if (objectp(haufen=present("\nhaufen "+
293 this_player()->name(WEM)))) {
294 obs = all_inventory(haufen);
295 }
296 // kein break;, Fall-through!
297 case "behaltenem":
298 case "behaltenes":
Zesstracc377ca2018-11-12 23:08:01 +0100299 obs += filter( my_inventory, "_behalten", ME,
MG Mud User88f12472016-06-24 23:31:02 +0200300 getuid(this_player() || previous_object()) );
301
302 obs += (QueryProp(P_ARMOURS) || ({}))
303 + ({ QueryProp(P_WEAPON) }) - ({ 0 });
304 break;
305
306 case "gegenstand":
Zesstracc377ca2018-11-12 23:08:01 +0100307 obs = my_inventory -
308 filter( my_inventory, #'living/*'*/ );
MG Mud User88f12472016-06-24 23:31:02 +0200309 break;
310
311 default:
Zesstracc377ca2018-11-12 23:08:01 +0100312 obs = filter_objects( my_inventory, "id", complex_desc );
MG Mud User88f12472016-06-24 23:31:02 +0200313 }
314
315 // unsichtbare objekte entfernen
316 obs = filter_objects( obs, "short" );
317
318 // letzten Gegenstand raussuchen
319 obs = obs[0..0];
320 } // if (letzter Gegenstand)
321 else
322 { // ganze Gruppen und nicht nur das letzte Objekt
323 switch ( complex_desc )
324 {
325 case "allem":
326 case "alles":
327 case "jeden gegenstand":
328 case "jedem gegenstand":
329 case "gegenstaende":
330 case "alle gegenstaende":
331 case "allen gegenstaenden":
332 if ( meth & POS_INVERS )
333 continue; // alles nicht = nichts :)
334
Zesstracc377ca2018-11-12 23:08:01 +0100335 obs = my_inventory -
336 filter( my_inventory, #'living/*'*/ );
MG Mud User88f12472016-06-24 23:31:02 +0200337 break;
338
339 case "waffen":
340 case "jede waffe":
341 case "jeder waffe":
342 case "alle waffen":
343 case "allen waffen":
Zesstracc377ca2018-11-12 23:08:01 +0100344 obs = filter_objects( my_inventory, "QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +0200345 P_WEAPON_TYPE );
346 break;
347
348 case "ruestungen":
349 case "jede ruestung":
350 case "jeder ruestung":
351 case "alle ruestungen":
352 case "allen ruestungen":
Zesstracc377ca2018-11-12 23:08:01 +0100353 obs = filter_objects( my_inventory, "QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +0200354 P_ARMOUR_TYPE );
355 break;
356
357 case "kleidung":
358 case "jede kleidung":
359 case "jeder kleidung":
360 case "alle kleidung":
361 case "allen kleidung":
Zesstracc377ca2018-11-12 23:08:01 +0100362 obs = filter_objects( my_inventory, "IsClothing");
MG Mud User88f12472016-06-24 23:31:02 +0200363 break;
364
365 case "gegenstand":
Zesstracc377ca2018-11-12 23:08:01 +0100366 obs = filter_objects( my_inventory -
367 filter( my_inventory,
MG Mud User88f12472016-06-24 23:31:02 +0200368 #'living/*'*/ ),
369 "short" )[0..0];
370 break;
371
372 case "verschiedenem":
373 case "verschiedenes":
Zesstracc377ca2018-11-12 23:08:01 +0100374 obs = my_inventory;
MG Mud User88f12472016-06-24 23:31:02 +0200375 obs -= filter_objects( obs, "QueryProp", P_WEAPON_TYPE );
376 obs -= filter_objects( obs, "QueryProp", P_ARMOUR_TYPE );
377 obs -= filter_objects( obs, "IsClothing");
378 obs -= filter( obs, #'living/*'*/ );
379 break;
380
381 case "eigenes":
382 case "eigenem":
383 case "eigenen":
384 case "meins":
385 case "alles eigene":
386 if (objectp(haufen=present("\nhaufen "+
387 this_player()->name(WEM)))) {
388 obs = all_inventory(haufen);
389 }
390 // kein break;, Fall-through!
391 case "behaltenem":
392 case "behaltenen":
393 case "behaltenes":
394 case "alles behaltene":
Zesstracc377ca2018-11-12 23:08:01 +0100395 obs += filter( my_inventory, "_behalten", ME,
MG Mud User88f12472016-06-24 23:31:02 +0200396 getuid(this_player() || previous_object()) );
397
398 obs += (QueryProp(P_ARMOURS) || ({}))
399 + ({ QueryProp(P_WEAPON) }) - ({ 0 });
400 break;
401
402 default:
403 if ( complex_desc[0..3] == "jede" ||
404 complex_desc[0..4] == "alle ")
405 {
406 if ( complex_desc[4..4] == " " )
407 {
Zesstracc377ca2018-11-12 23:08:01 +0100408 obs = filter_objects( my_inventory, "id",
MG Mud User88f12472016-06-24 23:31:02 +0200409 complex_desc[5..] );
410 break;
411 }
412 else
413 {
414 switch( complex_desc[4..5] )
415 {
416 case "m ":
417 case "r ":
418 case "n ":
419 case "s ":
Zesstracc377ca2018-11-12 23:08:01 +0100420 obs = filter_objects( my_inventory, "id",
MG Mud User88f12472016-06-24 23:31:02 +0200421 complex_desc[6..] );
422 break;
423
424 default:
425 obs = 0;
426 }
427 if (obs)
428 break;
429 }
430 }
431
432 // Der Normalfall: einzelne ID...
433 ob = present( complex_desc, ME );
Zesstracc377ca2018-11-12 23:08:01 +0100434 if (!ob)
435 ob = present_vitem(complex_desc);
MG Mud User88f12472016-06-24 23:31:02 +0200436 // Achtung: dieser Teil setzt das for() fort (continue) und
437 // umgeht dabei die Pruefung auf Sichtbarkeit nach dem Ende vom
438 // switch(). Aus diesem Grunde muss hier selber geprueft
439 // werden.
440 if ( meth & POS_INVERS )
441 {
442 if ( ob && ob != ME )
Zesstracc377ca2018-11-12 23:08:01 +0100443 erg += (filter_objects( my_inventory, "short" )
MG Mud User88f12472016-06-24 23:31:02 +0200444 - ({ ob }) );
445 else
Zesstracc377ca2018-11-12 23:08:01 +0100446 erg += filter_objects( my_inventory, "short" );
MG Mud User88f12472016-06-24 23:31:02 +0200447 }
Zesstracc377ca2018-11-12 23:08:01 +0100448 // Grund fuer P_INVIS statt short==0: Bei Angabe einer ganz
449 // bestimmten ID (im Gegensatz zu "alles", "jede waffe" etc.)
450 // soll ein Item gefunden werden, auch wenn die Short 0 ist
451 // (unsichtbar, aber interagierbar).
MG Mud User88f12472016-06-24 23:31:02 +0200452 else if ( ob && ob != ME && !ob->QueryProp(P_INVIS) )
453 erg += ({ ob }); //Normalfall: einzelne ID
454
455 continue;
456
457 } // switch
458 // unsichtbare objekte entfernen
459 obs = filter_objects( obs, "short" );
460 } // else
461
462 if ( meth & POS_INVERS )
Zesstracc377ca2018-11-12 23:08:01 +0100463 erg += ( filter_objects( my_inventory, "short" ) - obs );
MG Mud User88f12472016-06-24 23:31:02 +0200464 else
465 erg += obs;
466 } // for
467 return erg;
468}
469
470/*
471 * returns a list of all found objects inside itself
472 * may call same function in objects inside
473 *
474 * Funktion wird nicht mehr von put_and_get aufgerufen, stattdessen wird
475 * direkt present_objects benutzt!
476 */
Zesstra52d40932018-11-28 22:05:15 +0100477public object *locate_objects( string complex_desc, int info ) {
MG Mud User88f12472016-06-24 23:31:02 +0200478 string was, wo;
479
480 if ( sscanf( complex_desc, "%s in %s", was, wo ) == 2 ){
481 object *found_obs = ({});
482 foreach(object invob: present_objects(wo)) {
483 // || ({}) weil invob ein Objekt ohne locate_objects() sein koennte.
Zesstra231c3aa2020-03-08 12:43:20 +0100484 found_obs += ({object*})invob->locate_objects( was, info) || ({});
MG Mud User88f12472016-06-24 23:31:02 +0200485 }
486 return found_obs;
487 }
488 // kein "in" gefunden
489 return present_objects( complex_desc );
490}
491