blob: b9dcbf9a4b440b5715d9ca779e2df855a4290bbd [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>
Zesstracc377ca2018-11-12 23:08:01 +010036#include <container/vitems.h>
MG Mud User88f12472016-06-24 23:31:02 +020037
38// local properties prototypes
39static int _query_total_weight();
40
41
42private nosave int LastWeightCalc, contents, LastObjectCount, objcount;
43private nosave int last_content_change;
44
45
Zesstra52d40932018-11-28 22:05:15 +010046protected void create()
MG Mud User88f12472016-06-24 23:31:02 +020047{
48 Set( P_WEIGHT_PERCENT, 50 );
49 Set( P_TOTAL_WEIGHT, NOSETMETHOD, F_SET_METHOD );
50 Set( P_TOTAL_WEIGHT, PROTECTED, F_MODE );
51 Set( P_MAX_OBJECTS, 100 );
52 Set( P_TOTAL_OBJECTS, NOSETMETHOD, F_SET_METHOD );
53 Set( P_TOTAL_OBJECTS, PROTECTED, F_MODE );
54 LastWeightCalc = -1;
55 LastObjectCount = -1;
56}
57
58
59static int _query_last_content_change()
60{
61 return last_content_change;
62}
63
64
65// absichtlich public, da es von der simul_efun.c *direkt* aufgerufen
66// wird aus Performancegruenden!
67public varargs int _set_last_content_change( mixed wert )
68{
69 // Der uebergebene Wert ist unerheblich. Die Property
70 // P_LAST_CONTENT_CHANGE wird so oder so bei jedem SetProp()-
71 // Aufruf um eins erhoeht, um der 2s-"Unschaerfe" von time()
72 // aus dem Weg zu gehen.
73 return ++last_content_change;
74}
75
76
77int query_weight_contents()
78{
79 object *objs;
80 int w, w2, i;
81
82 if ( last_content_change == LastWeightCalc )
83 return contents;
84
85 w = 0;
86 objs = all_inventory(this_object());
87 i = sizeof(objs);
88
89 while ( i-- ){
90 if ( !(w2 = (int)objs[i]->QueryProp(P_TOTAL_WEIGHT)) )
91 w2 = (int)objs[i]->QueryProp(P_WEIGHT);
92 w += w2;
93 }
94
95 LastWeightCalc = last_content_change;
96 return contents = w;
97}
98
99
100static int _query_total_objects()
101{
102 if ( last_content_change == LastObjectCount )
103 return objcount;
104
105 objcount = sizeof( filter_objects( all_inventory(), "short" ) );
106 LastObjectCount = last_content_change;
107 return objcount;
108}
109
110
111// diese Funktion sollte von Raeumen natuerlich ueberschrieben werden...
Zesstra52d40932018-11-28 22:05:15 +0100112public int MayAddObject( object ob )
MG Mud User88f12472016-06-24 23:31:02 +0200113{
114 if (ob) {
115 if ( !ob->short() )
116 return 1; // invis-Objekte duerfen immer
117
118 if ( ob == ME || environment(ob) == ME)
119 return 1; // objekt ist schon drin
120 }
121
122 return (QueryProp(P_TOTAL_OBJECTS) < QueryProp(P_MAX_OBJECTS));
123}
124
125
126#define ENV environment
127#define PO previous_object()
128
Zesstra52d40932018-11-28 22:05:15 +0100129public int MayAddWeight( int w )
MG Mud User88f12472016-06-24 23:31:02 +0200130{
131 int nw, aw;
132
133 // was nix wiegt, passt
134 if ( w <= 0 )
135 return 0;
136
137 nw = w; // Gewicht im neuen Container
138 aw = 0; // Gewicht fuer das env()
139
140 // Von Raum in Behaelter im Spieler: Container sieht volles Gewicht (nw=w),
141 // Check im env() (Spieler) mit reduziertem Gewicht.
142 if ( ENV() && PO && ENV(PO) != ENV() )
143 aw = QueryProp(P_WEIGHT_PERCENT) * w / 100 || 1;
144
145 if ( PO && ENV(PO) && ENV(ENV(PO)) ){
146 // Wenn das Objekt ein env() hochbewegt wird, wird das Gewicht im alten
147 // Container abgezogen. Weiterer Check im env() ist unnoetig (aw=0).
148 if ( ENV(ENV(PO)) == ME )
149 nw = w - (int)ENV(PO)->QueryProp(P_WEIGHT_PERCENT) * w / 100;
150 // Eine Ebene tiefer bewegen: Test im neuen Container mit unveraendertem
151 // Gewicht; Check im env() mit um Gewichtsreduktion verringertem Gewicht
152 else if ( present( ME, ENV(PO) ) )
153 aw = QueryProp(P_WEIGHT_PERCENT) * w / 100 - w;
154 // Auf derselben Ebene verschieben (von Paket in Beutel):
155 // Neuer Container sieht volles Gewicht (nw=w), Check im env() mit
156 // Differenz aus Gewicht in Container1 und in Container2.
157 else if ( ENV(ENV(ENV(PO))) && ENV() == ENV(ENV(PO)) )
158 aw = QueryProp(P_WEIGHT_PERCENT) * w / 100
159 - ((int)ENV(PO)->QueryProp(P_WEIGHT_PERCENT) * w / 100 || 1);
160 }
161
162 if ( query_weight_contents() + nw > QueryProp(P_MAX_WEIGHT) )
163 // Container kann Gewicht nicht mehr aufnehmen
164 return -1;
165
166 if ( aw && ENV()->MayAddWeight(aw) < 0 )
167 // Umgebung des Containers kann Gewicht nicht mehr aufnehmen
168 return -2;
169
170 return 0;
171}
172
173
174/* Redefine PreventInsert() to prevent inserting of special objects. If
175 * a value greater 0 is returned the object ob can't be inserted in the
176 * container.
177 */
178public int PreventInsert( object ob ) { return 0; }
179public int PreventLeave( object ob, mixed dest ) { return 0; }
180public int PreventInsertLiving( object ob ) { return 0; }
181public int PreventLeaveLiving( object ob, mixed dest ) { return 0; }
182public void NotifyInsert(object ob, object oldenv) { }
Bugfixa5f76da2017-02-16 22:55:33 +0100183public void NotifyLeave(object ob, object dest) { }
MG Mud User88f12472016-06-24 23:31:02 +0200184
185// **** local property methods
186static int _query_total_weight()
187{
188 return QueryProp(P_WEIGHT) +
189 (QueryProp(P_WEIGHT_PERCENT) * query_weight_contents() / 100);
190}
191
192
193// Hilfsfunktion
194static int _behalten( object ob, string uid )
195{
196 return (string)ob->QueryProp(P_KEEP_ON_SELL) == uid;
197}
198
199
200/*
201 *
202 * get a list of all contained objects matching a complex description
203 *
204 */
205
206#define POS_INVERS 0x01 /* nur zur funktionsinternen Verwendung */
207#define POS_LETZTES 0x02 /* nur zur funktionsinternen Verwendung */
208
Zesstra52d40932018-11-28 22:05:15 +0100209public object *present_objects( string complex_desc )
MG Mud User88f12472016-06-24 23:31:02 +0200210{
211 int i; // Zaehlervariable
212 int meth; // 0x01 = invers?, 0x02 = letztes?
213 object ob; // einzelnes temporaeres Objekt
214 object *obs; // liste der ausgewaehlten Objekte
215 object *erg; // zum sammeln bis es nachher zurueckgegeben wird...
216 string *strlst; // liste aller Gruppen die mit AND verknuepft sind
217 object haufen;
218
219 strlst = allocate(2);
220
221 if ( sscanf( complex_desc, "%s ausser %s", strlst[0], strlst[1]) == 2 ){
222 erg = present_objects( strlst[0] );
223 obs = present_objects( strlst[1] );
224 return erg-obs;
225 }
226
227 strlst = explode( complex_desc, " und " );
228 erg = ({});
229
230 for ( i = sizeof(strlst); i--; )
231 {
232 complex_desc = strlst[i];
233 // auf letzte/letztes/letzten pruefen...
234 if ( complex_desc[0..5] == "letzte" ){
235 switch( complex_desc[6..6] ){
236 case " ":
237 meth |= POS_LETZTES;
238 complex_desc = complex_desc[7..];
239 break;
240 case "s":
241 case "n":
242 case "m":
243 case "r":
244 if ( complex_desc[7..7] != " " )
245 break;
246 meth |= POS_LETZTES;
247 complex_desc = complex_desc[8..];
248 break;
249 default:
250 }
251 }
252
253 // auf verneinung pruefen
254 if ( complex_desc[0..5] == "nicht " ){
255 meth |= POS_INVERS;
256 complex_desc = complex_desc[6..];
257 }
258
Zesstracc377ca2018-11-12 23:08:01 +0100259 obs = ({});
260 // all_inventory() und VItems (virtuell anwesende Items)
261 // zusammensammeln:
262 object *my_inventory = all_inventory() + GetVItemClones();
263
MG Mud User88f12472016-06-24 23:31:02 +0200264 // nun nach Main-Ids (Gruppen) suchen...
265 if ( meth & POS_LETZTES )
266 { // geht es nur um den letzten Gegenstand?
267 switch( complex_desc ){
268 case "waffe":
Zesstracc377ca2018-11-12 23:08:01 +0100269 obs = filter_objects( my_inventory, "QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +0200270 P_WEAPON_TYPE );
271 break;
272
273 case "ruestung":
Zesstracc377ca2018-11-12 23:08:01 +0100274 obs = filter_objects( my_inventory, "QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +0200275 P_ARMOUR_TYPE );
276 break;
277
278 case "kleidung":
Zesstracc377ca2018-11-12 23:08:01 +0100279 obs = filter_objects( my_inventory, "IsClothing");
MG Mud User88f12472016-06-24 23:31:02 +0200280 break;
281
282 case "verschiedenem":
283 case "verschiedenes":
Zesstracc377ca2018-11-12 23:08:01 +0100284 obs = my_inventory;
MG Mud User88f12472016-06-24 23:31:02 +0200285 obs -= filter_objects( obs, "QueryProp", P_WEAPON_TYPE );
286 obs -= filter_objects( obs, "QueryProp", P_ARMOUR_TYPE );
287 obs -= filter_objects( obs, "IsClothing");
288 obs -= filter( obs, #'living/*'*/ );
289 break;
290
291 case "eigenes":
292 case "meins":
293 if (objectp(haufen=present("\nhaufen "+
294 this_player()->name(WEM)))) {
295 obs = all_inventory(haufen);
296 }
297 // kein break;, Fall-through!
298 case "behaltenem":
299 case "behaltenes":
Zesstracc377ca2018-11-12 23:08:01 +0100300 obs += filter( my_inventory, "_behalten", ME,
MG Mud User88f12472016-06-24 23:31:02 +0200301 getuid(this_player() || previous_object()) );
302
303 obs += (QueryProp(P_ARMOURS) || ({}))
304 + ({ QueryProp(P_WEAPON) }) - ({ 0 });
305 break;
306
307 case "gegenstand":
Zesstracc377ca2018-11-12 23:08:01 +0100308 obs = my_inventory -
309 filter( my_inventory, #'living/*'*/ );
MG Mud User88f12472016-06-24 23:31:02 +0200310 break;
311
312 default:
Zesstracc377ca2018-11-12 23:08:01 +0100313 obs = filter_objects( my_inventory, "id", complex_desc );
MG Mud User88f12472016-06-24 23:31:02 +0200314 }
315
316 // unsichtbare objekte entfernen
317 obs = filter_objects( obs, "short" );
318
319 // letzten Gegenstand raussuchen
320 obs = obs[0..0];
321 } // if (letzter Gegenstand)
322 else
323 { // ganze Gruppen und nicht nur das letzte Objekt
324 switch ( complex_desc )
325 {
326 case "allem":
327 case "alles":
328 case "jeden gegenstand":
329 case "jedem gegenstand":
330 case "gegenstaende":
331 case "alle gegenstaende":
332 case "allen gegenstaenden":
333 if ( meth & POS_INVERS )
334 continue; // alles nicht = nichts :)
335
Zesstracc377ca2018-11-12 23:08:01 +0100336 obs = my_inventory -
337 filter( my_inventory, #'living/*'*/ );
MG Mud User88f12472016-06-24 23:31:02 +0200338 break;
339
340 case "waffen":
341 case "jede waffe":
342 case "jeder waffe":
343 case "alle waffen":
344 case "allen waffen":
Zesstracc377ca2018-11-12 23:08:01 +0100345 obs = filter_objects( my_inventory, "QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +0200346 P_WEAPON_TYPE );
347 break;
348
349 case "ruestungen":
350 case "jede ruestung":
351 case "jeder ruestung":
352 case "alle ruestungen":
353 case "allen ruestungen":
Zesstracc377ca2018-11-12 23:08:01 +0100354 obs = filter_objects( my_inventory, "QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +0200355 P_ARMOUR_TYPE );
356 break;
357
358 case "kleidung":
359 case "jede kleidung":
360 case "jeder kleidung":
361 case "alle kleidung":
362 case "allen kleidung":
Zesstracc377ca2018-11-12 23:08:01 +0100363 obs = filter_objects( my_inventory, "IsClothing");
MG Mud User88f12472016-06-24 23:31:02 +0200364 break;
365
366 case "gegenstand":
Zesstracc377ca2018-11-12 23:08:01 +0100367 obs = filter_objects( my_inventory -
368 filter( my_inventory,
MG Mud User88f12472016-06-24 23:31:02 +0200369 #'living/*'*/ ),
370 "short" )[0..0];
371 break;
372
373 case "verschiedenem":
374 case "verschiedenes":
Zesstracc377ca2018-11-12 23:08:01 +0100375 obs = my_inventory;
MG Mud User88f12472016-06-24 23:31:02 +0200376 obs -= filter_objects( obs, "QueryProp", P_WEAPON_TYPE );
377 obs -= filter_objects( obs, "QueryProp", P_ARMOUR_TYPE );
378 obs -= filter_objects( obs, "IsClothing");
379 obs -= filter( obs, #'living/*'*/ );
380 break;
381
382 case "eigenes":
383 case "eigenem":
384 case "eigenen":
385 case "meins":
386 case "alles eigene":
387 if (objectp(haufen=present("\nhaufen "+
388 this_player()->name(WEM)))) {
389 obs = all_inventory(haufen);
390 }
391 // kein break;, Fall-through!
392 case "behaltenem":
393 case "behaltenen":
394 case "behaltenes":
395 case "alles behaltene":
Zesstracc377ca2018-11-12 23:08:01 +0100396 obs += filter( my_inventory, "_behalten", ME,
MG Mud User88f12472016-06-24 23:31:02 +0200397 getuid(this_player() || previous_object()) );
398
399 obs += (QueryProp(P_ARMOURS) || ({}))
400 + ({ QueryProp(P_WEAPON) }) - ({ 0 });
401 break;
402
403 default:
404 if ( complex_desc[0..3] == "jede" ||
405 complex_desc[0..4] == "alle ")
406 {
407 if ( complex_desc[4..4] == " " )
408 {
Zesstracc377ca2018-11-12 23:08:01 +0100409 obs = filter_objects( my_inventory, "id",
MG Mud User88f12472016-06-24 23:31:02 +0200410 complex_desc[5..] );
411 break;
412 }
413 else
414 {
415 switch( complex_desc[4..5] )
416 {
417 case "m ":
418 case "r ":
419 case "n ":
420 case "s ":
Zesstracc377ca2018-11-12 23:08:01 +0100421 obs = filter_objects( my_inventory, "id",
MG Mud User88f12472016-06-24 23:31:02 +0200422 complex_desc[6..] );
423 break;
424
425 default:
426 obs = 0;
427 }
428 if (obs)
429 break;
430 }
431 }
432
433 // Der Normalfall: einzelne ID...
434 ob = present( complex_desc, ME );
Zesstracc377ca2018-11-12 23:08:01 +0100435 if (!ob)
436 ob = present_vitem(complex_desc);
MG Mud User88f12472016-06-24 23:31:02 +0200437 // Achtung: dieser Teil setzt das for() fort (continue) und
438 // umgeht dabei die Pruefung auf Sichtbarkeit nach dem Ende vom
439 // switch(). Aus diesem Grunde muss hier selber geprueft
440 // werden.
441 if ( meth & POS_INVERS )
442 {
443 if ( ob && ob != ME )
Zesstracc377ca2018-11-12 23:08:01 +0100444 erg += (filter_objects( my_inventory, "short" )
MG Mud User88f12472016-06-24 23:31:02 +0200445 - ({ ob }) );
446 else
Zesstracc377ca2018-11-12 23:08:01 +0100447 erg += filter_objects( my_inventory, "short" );
MG Mud User88f12472016-06-24 23:31:02 +0200448 }
Zesstracc377ca2018-11-12 23:08:01 +0100449 // Grund fuer P_INVIS statt short==0: Bei Angabe einer ganz
450 // bestimmten ID (im Gegensatz zu "alles", "jede waffe" etc.)
451 // soll ein Item gefunden werden, auch wenn die Short 0 ist
452 // (unsichtbar, aber interagierbar).
MG Mud User88f12472016-06-24 23:31:02 +0200453 else if ( ob && ob != ME && !ob->QueryProp(P_INVIS) )
454 erg += ({ ob }); //Normalfall: einzelne ID
455
456 continue;
457
458 } // switch
459 // unsichtbare objekte entfernen
460 obs = filter_objects( obs, "short" );
461 } // else
462
463 if ( meth & POS_INVERS )
Zesstracc377ca2018-11-12 23:08:01 +0100464 erg += ( filter_objects( my_inventory, "short" ) - obs );
MG Mud User88f12472016-06-24 23:31:02 +0200465 else
466 erg += obs;
467 } // for
468 return erg;
469}
470
471/*
472 * returns a list of all found objects inside itself
473 * may call same function in objects inside
474 *
475 * Funktion wird nicht mehr von put_and_get aufgerufen, stattdessen wird
476 * direkt present_objects benutzt!
477 */
Zesstra52d40932018-11-28 22:05:15 +0100478public object *locate_objects( string complex_desc, int info ) {
MG Mud User88f12472016-06-24 23:31:02 +0200479 string was, wo;
480
481 if ( sscanf( complex_desc, "%s in %s", was, wo ) == 2 ){
482 object *found_obs = ({});
483 foreach(object invob: present_objects(wo)) {
484 // || ({}) weil invob ein Objekt ohne locate_objects() sein koennte.
485 found_obs += (object *)invob->locate_objects( was, info) || ({});
486 }
487 return found_obs;
488 }
489 // kein "in" gefunden
490 return present_objects( complex_desc );
491}
492