blob: 00121b1404c2d0296df450d3a0012e248e10126c [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001//
2// pub.c -- Alles, was eine Kneipe braucht.
3//
4// $Id: pub.c 8778 2014-04-30 23:04:06Z Zesstra $
5// spendiere ueberarbeitet, 22.05.2007 - Miril
6#pragma strong_types
7#pragma save_types
MG Mud User88f12472016-06-24 23:31:02 +02008#pragma range_check
9#pragma no_clone
10
11#define NEED_PROTOTYPES
12#include <thing/commands.h>
13#include <thing/properties.h>
14
15#include <defines.h>
16#include <rooms.h>
17#include <properties.h>
18#include <routingd.h>
19#include <bank.h>
20#include <exploration.h>
21#include <wizlevels.h>
22#include <pub.h>
23
24// Alle nicht-privaten werden in erbenen Objekten verwendet.
25private nosave int max_list;
26private nosave int refresh_count;
27private nosave int sum;
28private nosave mapping refresh_list;
29nosave mapping id_list;
30nosave mapping menu_list;
31nosave object *waiting;
32
33#define PM_RATE_PUBMASTER "rate"
34#define PM_DELAY_PUBMASTER "delay"
35
36protected void create()
37{ object router;
38
39 SetProp( P_ROOM_TYPE, QueryProp(P_ROOM_TYPE) | RT_PUB );
40
41 SetProp( P_PUB_NOT_ON_MENU,
42 "Tut mir leid, das fuehren wir nicht! Wir sind ein anstaendiges "+
43 "Lokal!\n" );
44 SetProp( P_PUB_UNAVAILABLE,
45 "Davon ist leider nichts mehr da.\n" );
46 SetProp(P_PUB_NO_MONEY,
47 "Das kostet %d Goldstuecke, und Du hast nicht so viel!\n" );
48 SetProp(P_PUB_NO_KEEPER,
49 "Es ist niemand anwesend, der Dich bedienen koennte.\n");
50
51 AddCmd( "menue","menue" );
52 AddCmd( ({"kauf","kaufe","bestell","bestelle"}),"bestelle" );
53 AddCmd( ({"spendier","spendiere"}),"spendiere" );
54 AddCmd( "pubinit","pubinit" );
55
56 max_list=0;
57 refresh_count=0;
58 waiting = ({ });
59 id_list=([]);
60 menu_list=([]);
61 refresh_list=([]);
62
63 if ( !clonep(ME) && objectp(router=find_object(ROUTER)) )
64 router->RegisterTarget(TARGET_PUB,object_name(ME));
65
66 call_out("add_std_drinks",1);
67}
68
69protected void create_super() {
70 set_next_reset(-1);
71}
72
Bugfix80948172016-12-15 20:23:58 +010073// Die alten durch die neuen Platzhalter ersetzen
74private string replace_dummy(string str)
75{
76 switch(str)
77 {
78 case "&&": return "@WERU1";
79 case "&1&": return "@WERU1";
80 case "&2&": return "@WESSENU1";
81 case "&3&": return "@WEMU1";
82 case "&4& ": return "@WENU1";
83 case "&1#": return "@WERU1";
84 case "&2#": return "@WESSENU1";
85 case "&3#": return "@WEMU1";
86 case "&4# ": return "@WENU1";
87 case "&!": return "@WERQP1";
88 case "&5&": return "@WERQP1";
89 case "&6&": return "@WESSENQP1";
90 case "&7&": return "@WEMQP1";
91 case "&8&": return "@WENQP1";
92 case "&5#": return "@WERQP1";
93 case "&6#": return "@WESSENQP1";
94 case "&7#": return "@WEMQP1";
95 case "&8#": return "@WENQP1";
Bugfix80948172016-12-15 20:23:58 +010096 }
97 return str;
98}
99
MG Mud User88f12472016-06-24 23:31:02 +0200100/* Zur Syntax:
101 *
102 * menuetext - Der Text steht im Menue
103 *
104 * ids - Array der Namen, mit denen bestellt werden kann
105 *
106 * minfo - Mapping mit Eintraegen fuer:
107 * P_HP (HP-Heilung),
108 * P_SP (SP-Heilung),
109 * P_FOOD (Saettigung),
110 * P_DRINK (Fluessigkeit)
111 * P_ALCOHOL (Alkoholisierung)
112 * P_VALUE (Preis)
113 * Die Eintraege werden ueber eval_anything ausgewertet
114 * (siehe da)
115 *
116 * rate - Heilrate (auch ueber eavl_anything) in Punkte / heart_beat()
117 *
118 * msg - Meldung beim Essen.
119 * a) closure (wird mit funcall(msg,zahler,empfaenger)
120 * ausgewertet)
121 * b) string (wie closure: call_other(this_object...))
122 * c) array mit 2 strings: 1) fuer Essenden, 2) fuer andere
123 * siehe auch mess()
124 *
125 * refresh - Mapping mit den moeglichen Eintraegen:
126 * PR_USER : <Kontingent> ; <Update> (pro Spieler)
127 * PR_ALL : <Kontingent> ; <Update> (fuer alle)
128 * Es wird zunaechst geprueft, ob noch etwas fuer den
129 * (zahlenden!) Spieler selbst vorhanden ist wenn nein wird
130 * geschaut, ob das Kontingent fuer alle schon erschoepft ist.
131 * Sind beide Kontingente erschoepft, kann der Spieler das
132 * Bestellte nicht bekommen.
133 * Die Kontingente wird alle <Update> reset()s "aufgefrischt".
134 * <Kontingent> wird ueber eval_anything() ausgewertet.
135 * Alternativ kann man einen Int-Wert angeben. Dieser wird wie
136 * ([ PR_ALL : <wert> ; 1 ]) behandelt.
137 *
138 * delay - Zahl der Sekunden, um die verzoegert die Heilung eintritt
139 * z.B. weil das Essen erst zubereitet werden muss.
140 * Ebenfalls ueber eval_anything()
141 *
142 * d_msg - Meldung beim bestellen, falls Delay. Wie msg.
143 */
144varargs string AddToMenu(string menuetext, mixed ids, mapping minfo,
145 mixed rate, mixed msg, mixed refresh,
146 mixed delay, mixed d_msg)
147{ string ident;
148 int i;
149
150 if ( !stringp(menuetext) || !ids || !mappingp(minfo) )
151 return 0;
152
153 if ( stringp(ids) )
154 ids = ({ ids });
155 else if ( !pointerp(ids) )
156 return 0;
157
158 ident = sprintf("menuentry%d",max_list);
159 max_list++;
160
161 /* Fuer schnelles Nachschlagen ein eigenes Mapping fuer Ids */
162 for( i=sizeof(ids)-1;i>=0;i-- )
163 id_list += ([ ids[i] : ident ]);
164
Bugfix80948172016-12-15 20:23:58 +0100165 if(pointerp(msg) && sizeof(msg)>=2)
166 {
167 msg[0]=regreplace(msg[0],"[&][1-8,&,#,!]*", #'replace_dummy, 1);
168 msg[1]=regreplace(msg[1],"[&][1-8,&,#,!]*", #'replace_dummy, 1);
169 }
170
171 if(pointerp(d_msg) && sizeof(d_msg)>=2)
172 {
heull001fead4d72017-06-17 22:39:43 +0200173 d_msg[0]=regreplace(d_msg[0],"[&][1-8,&,#,!]*", #'replace_dummy, 1);
174 d_msg[1]=regreplace(d_msg[1],"[&][1-8,&,#,!]*", #'replace_dummy, 1);
Bugfix80948172016-12-15 20:23:58 +0100175 }
176
MG Mud User88f12472016-06-24 23:31:02 +0200177 if ( intp(refresh) && (refresh>0) )
178 refresh = ([ PR_ALL : refresh; 1 ]);
179 else if ( !mappingp(refresh) )
180 refresh = 0;
181
182 menu_list += ([ ident : menuetext; minfo; rate; msg; refresh;
183 delay; d_msg; ids ]);
184 return ident;
185}
186
187// Diese Methode ist nur noch aus Kompatibilitaetsgruenden vorhanden und darf
188// nicht mehr verwendet werden!!!
Zesstraa29b2cd2020-08-17 20:55:39 +0200189deprecated void AddFood(string nameOfFood, mixed ids, int price, int heal,
MG Mud User88f12472016-06-24 23:31:02 +0200190 mixed myFunction)
191{
192 if ( !nameOfFood || !ids || !price)
193 return; /* Food not healing is ok ! */
194
195 AddToMenu( nameOfFood,ids,
196 ([ P_VALUE : price, P_FOOD : heal, P_HP : heal, P_SP : heal ]),
197 ((heal>5)?5:heal), myFunction, 0,0,0);
198}
199
200// Diese Methode ist nur noch aus Kompatibilitaetsgruenden vorhanden und darf
201// nicht mehr verwendet werden!!!
Zesstraa29b2cd2020-08-17 20:55:39 +0200202deprecated void AddDrink(string nameOfDrink, mixed ids, int price, int heal,
MG Mud User88f12472016-06-24 23:31:02 +0200203 int strength, int soak, mixed myFunction)
204{
205 if ( !nameOfDrink || !ids || !price )
206 return;
207
208 heal=heal/2;
209 /* Kleine Korrektur, damit man in alten Pubs ueberhaupt trinken kann */
210 AddToMenu(nameOfDrink,ids,
211 ([ P_VALUE : price, P_DRINK : soak, P_ALCOHOL : strength,
212 P_HP : heal, P_SP : heal ]),
213 ((heal>5)?5:heal), myFunction,0,0,0);
214}
215
216int RemoveFromMenu(mixed ids) {
217 int ret;
218
219 if (stringp(ids))
220 ids = ({ids});
221
222 if (pointerp(ids)) {
223 foreach (string id: ids) {
224 // look if the id has a matching ident
225 string ident = id_list[id];
226 if (stringp(ident)) {
227 // remove this ident-entry from the id-list ...
228 m_delete(id_list, id);
229 // ... and remove all others now too (so it won't bug later, if
230 // the wizard calling this method forgot an id)
231 foreach (string listid: m_indices(id_list))
232 if (id_list[listid] == ident)
233 m_delete(id_list, listid);
234
235 // now remove the ident from the menu_list
236 if (member(menu_list, ident)) {
237 ret++;
238 m_delete(menu_list, ident);
239
240 // decrease the ident-counter, if this entry was the last one
241 int oldnum;
242 if (sscanf(ident, "menuentry%d", oldnum) == 1 &&
243 oldnum == (max_list-1))
244 max_list--;
245 }
246 }
247 }
248 }
249 // return removed entries
250 return ret;
251}
252
253/* Zum Auswerten der Eintraege fuer Preis, Rate, HP...
254 * a) integer-Wert -> wird direkt uebernommen
255 * b) mapping -> Wird als RaceModifiere verstanden. Es wird der
256 * Eintrag gewaehlt, der der Rasse des Spielers
257 * entspricht, falls vorhanden, ansonsten der Eintrag
258 * fuer 0.
259 * c) Array -> In erstem Element (muss Objekt oder dessen Filename
260 * sein) wird die Funktion mit dem Namen im 2.Element
261 * aufgerufen.
262 * d) String -> Die genannte Funktion wird in der Kneipe selbst
263 * aufgerufen.
264 * e) Closure -> Die Closure wird ausgewertet.
265 * Alle Funktionsaufrufe bekommen den essenden Spieler (bei Price und Delay
266 * den bestellenden Spieler) als Argument uebergeben. Die Auswertung erfolgt
267 * in der angegebenen Reihenfolge. Am Ende muss ein Intergerwert herauskommen
268 */
269int eval_anything(mixed what, object pl)
270{ mixed re;
271
272 if (intp(what))
273 return what;
274
275 if (mappingp(what) && pl)
276 {
277 re = what[pl->QueryProp(P_RACE)]||what[0];
278 }
279
280 if (re)
281 what=re;
282
283 if ( pointerp(what) && (sizeof(what)>=2)
284 && ( objectp(what[0]) || stringp(what[0]) )
285 && stringp(what[1]) )
286 what = call_other(what[0],what[1],pl);
287
288 if ( stringp(what) && function_exists(what,ME) )
289 what = call_other(ME,what,pl);
290
291 if ( closurep(what) )
292 what = funcall(what,pl);
293
294 if ( intp(what) )
295 return what;
296
297 return 0;
298}
299
300/* Diese Funktion ueberprueft, ob das Kontingent eines Menueeintrags
301 * fuer einen Spieler erschoepft ist.
302 */
303string CheckAvailability(string ident, object zahler)
304{ string uid;
305
306 if ( !stringp(ident) || !member(menu_list,ident) || !objectp(zahler) )
307 return 0;
308 if ( !mappingp(menu_list[ident,PM_REFRESH]) )
309 return PR_NONE;
310
311 if ( !member(refresh_list,ident) )
312 refresh_list += ([ ident : ([ ]) ]);
313
314 if ( query_once_interactive(zahler) )
315 uid=getuid(zahler);
316 else
317 uid=object_name(zahler);
318
319 if ( member(menu_list[ident,PM_REFRESH],PR_USER) )
320 {
321 if ( !member(refresh_list[ident],uid) )
322 {
323 refresh_list[ident] += ([ uid : 0 ; refresh_count ]);
324 }
325
326 /* Kontingent des Zahlenden pruefen */
327 if ( refresh_list[ident][uid,PRV_AMOUNT] <
328 eval_anything(menu_list[ident,PM_REFRESH][PR_USER,PRV_AMOUNT],
329 zahler) )
330 return uid;
331 }
332
333 if ( member(menu_list[ident,PM_REFRESH],PR_ALL) )
334 {
335 if ( !member(refresh_list[ident],PR_DEFAULT) )
336 {
337 refresh_list[ident] += ([ PR_DEFAULT : 0 ; refresh_count ]);
338 }
339
340 /* Kontingent der Allgemeinheit pruefen */
341 if ( refresh_list[ident][PR_DEFAULT,PRV_AMOUNT] <
342 eval_anything(menu_list[ident,PM_REFRESH][PR_ALL,PRV_AMOUNT],
343 zahler) )
344 return PR_DEFAULT;
345 }
346
347 return 0;
348}
349
350/* Diese Funktion reduziert das Kontingent des Lebewesens uid beim
351 * Menueeintrag ident um 1
352 */
353void DecreaseAvailability(string ident, string uid)
354{
355 if ( !stringp(ident) || !stringp(uid) )
356 return;
357 refresh_list[ident][uid,PRV_AMOUNT]++;
358}
359
360/* Diese Funktion sorgt dafuer, dass die Kontingente an limitierten
361 * Sachen in regelmaessigen Abstaenden wiederhergestellt werden.
362 */
363static void UpdateAvailability()
364{ int i1,i2;
365 string *ind1,*ind2,chk;
366
367 /* Keine Refresh-Eintraege, kein Update */
368 if ( !mappingp(refresh_list)
369 || (i1=sizeof(ind1=m_indices(refresh_list)))<1 )
370 return;
371
372 /* Es muss jeder Menueeintrag, der in der refresh_list steht,
373 * durchgegangen werden.
374 */
375 for ( --i1 ; i1>=0 ; i1-- )
376 {
377 if ( !mappingp(refresh_list[ind1[i1]])
378 || (i2=sizeof(ind2=m_indices(refresh_list[ind1[i1]])))<1 )
379 continue;
380
381 /* Fuer jeden Menueeintrag muss jeder Spielereintrag durchgegangen
382 * werden, der in dem entspr. mapping steht.
383 */
384 for ( --i2 ; i2>=0 ; i2-- ) // Alle Spieler
385 {
386 if ( ind2[i2]==PR_DEFAULT )
387 chk = PR_ALL;
388 else
389 chk = PR_USER;
390
391 if ( ( refresh_list[ind1[i1]][ind2[i2],PRV_REFRESH]
392 + menu_list[ind1[i1],PM_REFRESH][chk,PRV_REFRESH] )
393 <= refresh_count )
394 {
395 refresh_list[ind1[i1]][ind2[i2],PRV_AMOUNT]=0;
396 refresh_list[ind1[i1]][ind2[i2],PRV_REFRESH]=refresh_count;
397 }
398 }
399 }
400}
401
402mixed DBG(mixed o) {
403 if(find_player("rumata"))
404 tell_object(
405 find_player("rumata"),
406 sprintf("DBG: %O\n", o)
407 );
408 return 0;
409}
410
411/* Erweitert um die Moeglichkeit, Speise- oder Getraenke-Karte zu sehen. */
412string menue_text(string str)
413{ int i,sdr,sfo;
414 string ident,res;
415 string *fo=({}),*dr=({});
416
417 if ( !max_list )
418 return "Hier scheint es derzeit nichts zu geben.\n";
419
420 if ( !stringp(str) || str=="" )
421 str="alles";
422
423 /* Fuers Menue entscheiden ob Drink oder Food */
424 foreach(string id, string menuetext, mapping minfo: menu_list)
425 {
426 if (eval_anything(minfo[P_FOOD],this_player()))
427 fo+=({ id });
428 else
429 dr+=({ id });
430 }
431
432 sdr = sizeof(dr);
433 sfo = sizeof(fo);
434
435 if ( member(({"alle","alles"}),str)!=-1)
436 {
437 if ( !sfo )
438 str="drinks";
439 else if ( !sdr )
440 str="speise";
441 else
442 {
443 /* Gemischte Karte */
444 res = "Getraenke Preis alc | "+
445 "Speisen Preis\n"+
446 "---------------------------------------+-"+
447 "--------------------------------------\n";
448
449 for ( i=0 ; ( i<sdr || i<sfo ) ; i++ )
450 {
451 if ( i<sdr )
452 res += sprintf("%-29.29s%5.5d %c | ",
453 menu_list[dr[i],PM_TEXT],
454 eval_anything(menu_list[dr[i],PM_INFO][P_VALUE],PL),
455 (eval_anything(menu_list[dr[i],PM_INFO][P_ALCOHOL],PL)>0) ? 'J' : 'N');
456 else
457 res += " | ";
458
459 if ( i<sfo )
460 res += sprintf("%-33.33s%5.5d",
461 menu_list[fo[i],PM_TEXT],
462 eval_anything(menu_list[fo[i],PM_INFO][P_VALUE],PL));
463
464 res += "\n";
465 }
466
467 return res;
468 }
469 }
470
471 /* Reine Getraenkekarte */
472 if ( member(({"getraenke","drinks","getraenk","trinken"}),str)!=-1 )
473 {
474 if ( !sdr )
475 return "Hier gibt es leider nichts zu trinken.\n";
476
477 res = "Getraenke Preis alc | "+
478 "Getraenke Preis alc\n"+
479 "---------------------------------------+-"+
480 "--------------------------------------\n";
481
482 for ( i=0 ; i<sdr ; i++ )
483 {
484 ident = dr[i];
485
486 if ( !eval_anything(menu_list[ident,PM_INFO][P_FOOD], PL) )
487 res += sprintf("%-29.29s%5.5d %c%s",
488 menu_list[ident,PM_TEXT],
489 eval_anything(menu_list[ident,PM_INFO][P_VALUE],PL),
490 (eval_anything(menu_list[ident,PM_INFO][P_ALCOHOL],PL)>0) ? 'J' : 'N',
491 ((i%2)?"\n":" | "));
492 }
493
494 if ( res[<1..<1]!="\n" )
495 res += "\n";
496
497 return res;
498 }
499
500 /* Reine Speisekarte */
501 if ( member(({"speise","speisen","essen"}),str)!=-1 )
502 {
503 if ( !sfo )
504 return "Hier gibt es leider nichts zu essen.\n";
505
506 res = "Speisen Preis | "+
507 "Speisen Preis\n"+
508 "---------------------------------------+-"+
509 "--------------------------------------\n";
510
511 for ( i=0 ; i<sfo ; i++ )
512 {
513 ident = fo[i];
514 if (eval_anything(menu_list[ident,PM_INFO][P_FOOD],PL) )
515 res += sprintf("%-33.33s%5.5d%s",
516 menu_list[ident,PM_TEXT],
517 eval_anything(menu_list[ident,PM_INFO][P_VALUE],PL),
518 ((i%2)?"\n":" | "));
519 }
520
521 if ( res[<1..<1]!="\n" )
522 res += "\n";
523
524 return res;
525 }
526
527 return 0;
528}
529
530int menue(string str)
531{ string txt;
532
533 _notify_fail("Welchen Teil des Menues moechtest Du sehen?\n");
534 if ( !stringp(txt=menue_text(str)) || sizeof(txt)<1 )
535 return 0;
536 write(txt);
537 return 1;
538}
539
540/* Diese Funktion kann/soll bei Bedarf ueberladen werden, um simultane
541 * Aenderungen des Mappings zu ermoeglichen (zu Beispiel wie es in guten
542 * Tagen groesser Portionen gib, Hobbits per se mehr kriegen, ...
543 */
544mapping adjust_info(string ident, mapping minfo, object zahler,
545 object empfaenger)
546{
547 return 0;
548}
549
Bugfix80948172016-12-15 20:23:58 +0100550
MG Mud User88f12472016-06-24 23:31:02 +0200551string mess(string str,object pl)
552{
MG Mud User88f12472016-06-24 23:31:02 +0200553 if ( !pl )
554 pl=PL;
555
556 if ( !stringp(str) || str=="" )
557 return str;
558
Bugfix80948172016-12-15 20:23:58 +0100559 str=replace_personal(str,({pl}),1);
MG Mud User88f12472016-06-24 23:31:02 +0200560
561 return break_string(capitalize(str),78,"", BS_LEAVE_MY_LFS);
562}
563
564protected void _copy_menulist_values(mapping entryinfo, string ident) {
565 /* Kopieren aller Werte ins minfo-Mapping, um Problemen bei Loeschung
566 aus dem Weg zu gehen. Slow and dirty */
567 entryinfo[PM_TEXT] = deep_copy(menu_list[ident, PM_TEXT]);
568 // PM_INFO is already flat in entryinfo
569 entryinfo[PM_RATE_PUBMASTER]
570 = deep_copy(menu_list[ident, PM_RATE]);
571 entryinfo[PM_SERVE_MSG] = deep_copy(menu_list[ident, PM_SERVE_MSG]);
572 entryinfo[PM_REFRESH] = deep_copy(menu_list[ident, PM_REFRESH]);
573 // PM_DELAY is already evaluated in entryinfo
574 entryinfo[PM_DELAY_MSG] = deep_copy(menu_list[ident, PM_DELAY_MSG]);
575 entryinfo[PM_IDS] = deep_copy(menu_list[ident, PM_IDS]);
576}
577
578int do_deliver(string ident, object zahler, object empfaenger,
579 mapping entryinfo) {
580 waiting -= ({ empfaenger,0 });
581
582 /* Empfaenger muss natuerlich noch da sein */
583 if ( !objectp(empfaenger) || !present(empfaenger) )
584 return 0;
585
586 /* Zahler wird nur wegen der Abwaertskompatibilitaet gebraucht */
587 if ( !objectp(zahler) )
588 zahler = empfaenger;
589
590 // alte Pubs, die do_deliver irgendwie selbst aufrufen, sollten
591 // mit der Zeit korrigiert werden
592 if(!mappingp(entryinfo))
593 raise_error("Pub ruft do_deliver() ohne sinnvolle Argumente auf.\n");
594 if(!member(entryinfo, PM_RATE_PUBMASTER)) {
595 if(!member(menu_list, ident))
596 raise_error("Pub ruft do_deliver() mit geloeschtem Getraenk und "
597 "teilweisen Argumenten auf!\n");
598
599 _copy_menulist_values(entryinfo, ident);
600 call_out(#'raise_error, 1,
601 "Pub ruft do_deliver() nur mit teilweisen Argumenten auf.\n");
602 }
603
604 entryinfo[PM_RATE_PUBMASTER] = eval_anything(entryinfo[PM_RATE_PUBMASTER],
605 empfaenger);
606 entryinfo[P_HP] = eval_anything(entryinfo[P_HP], empfaenger);
607 entryinfo[P_SP] = eval_anything(entryinfo[P_SP], empfaenger);
608
609 /* Ueberpruefen, ob Heilmoeglichkeit legal */
610 if ( query_once_interactive(empfaenger)
611 && ((PUBMASTER->RegisterItem(entryinfo[PM_TEXT], entryinfo))<1) ) {
612 tell_object(empfaenger,
613 "Mit diesem Getraenk/Gericht scheint etwas nicht in Ordnung "+
614 "zu sein.\nVerstaendige bitte den Magier, der fuer diesen "+
615 "Raum verantwortlich ist.\n");
616 return -4;
617 }
618
619 if ( QueryProp(P_NPC_FASTHEAL) && !query_once_interactive(empfaenger) ) {
620 entryinfo[H_DISTRIBUTION] = HD_INSTANT;
621 }
622 else {
623 entryinfo[H_DISTRIBUTION] = entryinfo[PM_RATE_PUBMASTER];
624 }
625 empfaenger->consume(entryinfo);
626
627 /* Meldung ausgeben */
628 /* Hinweis: Da die ausfuehrenden Funktionen auch ident und minfo
629 * uebergeben bekommen, kann man hier auch ueber adjust_info oder
630 * an anderer Stelle zusaetzliche Informationen uebergeben...
631 */
632 if (closurep(entryinfo[PM_SERVE_MSG]) )
633 funcall(entryinfo[PM_SERVE_MSG], zahler, empfaenger, ident, entryinfo);
634 else if (stringp(entryinfo[PM_SERVE_MSG]) &&
635 function_exists(entryinfo[PM_SERVE_MSG],ME))
636 call_other(ME, entryinfo[PM_SERVE_MSG], zahler, empfaenger, ident,
637 entryinfo);
638 else if (pointerp(entryinfo[PM_SERVE_MSG]) &&
639 sizeof(entryinfo[PM_SERVE_MSG])>=2) {
640 if (stringp(entryinfo[PM_SERVE_MSG][0]) &&
641 sizeof(entryinfo[PM_SERVE_MSG][0]))
642 tell_object(empfaenger,
643 mess(entryinfo[PM_SERVE_MSG][0]+"\n", empfaenger));
644 if (stringp(entryinfo[PM_SERVE_MSG][1]) &&
645 sizeof(entryinfo[PM_SERVE_MSG][1]))
646 tell_room(environment(empfaenger)||ME,
647 mess(entryinfo[PM_SERVE_MSG][1]+"\n",empfaenger),
648 ({empfaenger}) );
649 }
650
651 return 1;
652}
653
654/* Testet, ob genug Geld zur Verfuegung steht.
655 * Falls die Bonitaet anderen Beschraenkungen unterliegt, als
656 * dass der Zahler genug Geld dabei hat, muss diese Methode
657 * ueberschrieben werden.
658 * Rueckgabewerte:
659 * -2 : Out of Money
660 * 0 : Alles OK.
661 * Rueckgabewerte != 0 fuehren zu einem Abbruch der Bestellung
662 */
663int CheckSolvency(string ident, object zahler, object empfaenger,
664 mapping entryinfo)
665{
666 if ( (zahler->QueryMoney())<entryinfo[P_VALUE] )
667 {
668 string res;
669 if ( !stringp(res=QueryProp(P_PUB_NO_MONEY)) )
670 res = "Das kostet %d Goldstuecke, und Du hast nicht so viel!\n";
671 tell_object(zahler,sprintf(res, entryinfo[P_VALUE]));
672 return -2;
673 }
674 return 0;
675}
676
677/* Fuehrt die Bezahlung durch.
678 * Falls die Bezahlung anders erfolgt, als durch Abzug des Geldes vom Zahler,
679 * muss diese Methode ueberschrieben werden
680 * Rueckgabewerte:
681 * Anzahl der Muenzen, die im Pub landen und bei Reset in die Zentralbank
682 * eingezahlt werden
683 */
684int DoPay(string ident, object zahler, object empfaenger, mapping entryinfo)
685{
686 zahler->AddMoney(-entryinfo[P_VALUE]);
687 return entryinfo[P_VALUE];
688}
689
690/* Rueckgabewerte:
691 * -6 : Nicht vorraetig
692 * -5 : Wirt nicht anwesend
693 * -4 : Illegales Getraenk/Gericht. Ausgabe verweigert.
694 * Nur bei sofortiger Lieferung...
695 * -3 : Empfaenger bereits voll
696 * -2 : Out of Money
697 * -1 : spendieren ignoriert
698 * 0 : Empfaenger ausgeflogen (sollte eigentlich nicht passieren)
699 * 1 : Alles OK.
700 */
701int consume_something(string ident, object zahler, object empfaenger) {
702 if ( !objectp(zahler) )
703 zahler=PL;
704
705 if ( !objectp(empfaenger) )
706 empfaenger=PL;
707
708 /* Die Abfrage auf anwesenden Wirt erfolgt NUR an dieser Stelle, damit */
709 /* kein Spieler darunter leiden muss, wenn jemand anderes zwischen */
710 /* Bestellung und Lieferung den Wirt meuchelt. */
711 if ( stringp(QueryProp(P_KEEPER)) && !present(QueryProp(P_KEEPER), ME))
712 {
713 string res = QueryProp(P_PUB_NO_KEEPER);
714 if ( !stringp(res) ) {
715 res = "Es ist niemand anwesend, der Dich bedienen koennte.\n";
716 }
717 tell_object(zahler,res);
718 return -5;
719 }
720
721 /* Spendiert und ignoriert? */
722 if ( zahler!=empfaenger )
723 {
724 mixed res = ({"spendiere"});
725 if ( eval_anything(menu_list[ident,PM_INFO][P_DRINK],empfaenger) )
726 res += ({"spendiere.getraenke"});
727 if ( eval_anything(menu_list[ident,PM_INFO][P_FOOD],empfaenger) )
728 res += ({"spendiere.essen"});
729 if ( eval_anything(menu_list[ident,PM_INFO][P_ALCOHOL],empfaenger) )
730 res += ({"spendiere.alkohol"});
731 if ( empfaenger->TestIgnoreSimple(res) )
732 {
733 tell_object(zahler,
734 empfaenger->Name(WER)+" will das nicht.\n");
735 return -1;
736 }
737 }
738
739 /* Hier kann das Info-Mapping erst mal als ganzes angepasst werden. */
740 mapping xinfo;
741 mapping entryinfo = deep_copy(menu_list[ident, PM_INFO]);
742 if ( (xinfo=adjust_info(ident,entryinfo,zahler,empfaenger)) &&
743 mappingp(xinfo) )
744 entryinfo += xinfo;
745
746 /* Genug Geld vorhanden? */
747 entryinfo[P_VALUE] = eval_anything(entryinfo[P_VALUE], zahler);
748 {
749 int res = CheckSolvency(ident, zahler, empfaenger, entryinfo);
750 if (res != 0) return res;
751 }
752
753 string avb;
754 if ( !stringp(avb=CheckAvailability(ident, zahler)) )
755 {
756 string res = QueryProp(P_PUB_UNAVAILABLE);
757 if ( !stringp(res) )
758 res = "Davon ist leider nichts mehr da.\n";
759 tell_object(zahler,res);
760 return -6;
761 }
762
763 /* Textausgabe beim spendieren */
764 if ( empfaenger!=zahler)
765 {
766 tell_room(environment(empfaenger)||ME,
767 zahler->Name(WER)+" spendiert "+empfaenger->name(WEM)+" etwas.\n",
768 ({zahler, empfaenger}) );
769 tell_object(empfaenger,
770 zahler->Name(WER)+" spendiert Dir etwas.\n");
771 tell_object(zahler,
772 "Du spendierst "+empfaenger->name(WEM)+" etwas.\n");
773 }
774
775 /* Testen, ob mans noch essen / trinken kann */
776 /* Die int-Werte werden in minfo uebernommen fuer die Auswertung */
777 /* im Pubmaster. */
778 entryinfo[P_FOOD] = eval_anything(entryinfo[P_FOOD], empfaenger);
779 entryinfo[P_ALCOHOL] = eval_anything(entryinfo[P_ALCOHOL],empfaenger);
780 entryinfo[P_DRINK] = eval_anything(entryinfo[P_DRINK], empfaenger);
781
782 int result = empfaenger->consume(entryinfo, 1);
783 if (result < 0) {
784 if (result & HC_MAX_FOOD_REACHED)
785 tell_object(empfaenger,
786 "Du bist zu satt, das schaffst Du nicht mehr.\n");
787 else if (result & HC_MAX_DRINK_REACHED)
788 tell_object(empfaenger,
789 "So viel kannst Du im Moment nicht trinken.\n");
790 else if (result & HC_MAX_ALCOHOL_REACHED)
791 tell_object(empfaenger,
792 "Soviel Alkohol vertraegst Du nicht mehr.\n");
793 return -3;
794 }
795
796 /* Gezahlt wird auch sofort */
797 sum += DoPay(ident, zahler, empfaenger, entryinfo);
798
799 /* FPs gibts auch sofort */
800 if (zahler == empfaenger)
801 GiveEP(EP_PUB,menu_list[ident,PM_IDS][0]);
802
803 /* Falls die Anzahl des Bestellten beschraenkt ist, muss diese natuerlich
804 * angepasst werden.
805 */
806 if ( avb!=PR_NONE )
807 DecreaseAvailability(ident,avb);
808
809 /* Gibt es eine Zeitverzoegerung zwischen Bestellen und Servieren? */
810 entryinfo[PM_DELAY_PUBMASTER] = eval_anything(menu_list[ident, PM_DELAY], zahler);
811
812 // alle fuer einen Drink notwendigen Werte kopieren
813 _copy_menulist_values(entryinfo, ident);
814
815 if (entryinfo[PM_DELAY_PUBMASTER]<=0)
816 return do_deliver(ident,zahler,empfaenger,entryinfo);
817
818 /* Bestell-Meldung ausgeben */
819 if (closurep(entryinfo[PM_DELAY_MSG]))
820 funcall(entryinfo[PM_DELAY_MSG], zahler, empfaenger,ident, entryinfo);
821 else if (stringp(entryinfo[PM_DELAY_MSG]) &&
822 function_exists(entryinfo[PM_DELAY_MSG],ME))
823 call_other(ME, entryinfo[PM_DELAY_MSG], zahler, empfaenger, ident,
824 entryinfo);
825 else if (pointerp(entryinfo[PM_DELAY_MSG]) &&
826 sizeof(entryinfo[PM_DELAY_MSG])>=2) {
827 if (stringp(entryinfo[PM_DELAY_MSG][0]) &&
828 sizeof(entryinfo[PM_DELAY_MSG][0]))
829 tell_object(empfaenger,
830 mess(entryinfo[PM_DELAY_MSG][0]+"\n",empfaenger));
831 if (stringp(entryinfo[PM_DELAY_MSG][1]) &&
832 sizeof(entryinfo[PM_DELAY_MSG][1]))
833 tell_room(environment(empfaenger)||ME,
834 mess(entryinfo[PM_DELAY_MSG][1]+"\n",empfaenger),
835 ({empfaenger}) );
836 }
837
838 waiting += ({ empfaenger });
839 call_out("do_deliver", entryinfo[PM_DELAY_PUBMASTER],
840 ident, zahler, empfaenger, entryinfo);
841
842 return 1;
843}
844
845/* Rueckgabewere: 0: Nicht im Menue gefunde, 1 sonst */
846int search_what(string str,object zahler,object empfaenger)
847{ string ident;
848
849 if ( member(waiting,empfaenger)!=-1 )
850 {
851 if ( PL==empfaenger )
852 write("Du wartest doch noch auf etwas!\n");
853 else
854 write(empfaenger->Name(WER,2)+" wartet noch auf etwas.\n");
855 return 1;
856 }
857
858 str = lower_case(str);
859 if ( ident=id_list[str] )
860 {
861 consume_something(ident,zahler,empfaenger);
862 return 1;
863 }
864
865 return 0;
866}
867
868// Neue Version von Mesi:
869int spendiere(string str)
870{
871 _notify_fail("spendiere <spieler> <drink>\n");
872
873 if ( !stringp(str) || str=="" )
874 return 0;
875
876 string who,what;
877 int whoidx;
878
879 if (sscanf(str,"%s %d %s",who,whoidx,what)!=3
880 && sscanf(str,"%s %s",who,what)!=2)
881 return 0;
882 object target=present(who, whoidx);
883 if(!target && this_player()) target=present(who, whoidx, this_player());
884 if ( !target || !living(target) )
885 {
886 write("Das Lebewesen ist nicht hier...\n");
887 return 1;
888 }
889
bugfixaf2be4f2020-03-22 19:13:07 +0100890 notify_fail(QueryProp(P_PUB_NOT_ON_MENU)||"So etwas gibt es hier nicht!\n");
MG Mud User88f12472016-06-24 23:31:02 +0200891
892 return search_what(what,PL,target);
893}
894
895int bestelle(string str)
896{
bugfixaf2be4f2020-03-22 19:13:07 +0100897 notify_fail(QueryProp(P_PUB_NOT_ON_MENU));
MG Mud User88f12472016-06-24 23:31:02 +0200898
899 if ( !stringp(str) )
900 return 0;
901
902 return search_what(str,PL,PL);
903}
904
905int pubinit()
906{ string *liste,ident,fn;
907 int si,erg,max;
908 mapping minfo,xinfo;
909
910 if ( !PL || !IS_WIZARD(PL) )
911 return 0;
912
913 si=sizeof(liste=sort_array(m_indices(menu_list),#'<));
914 if ( si<1 )
915 return notify_fail("Keine Gerichte/Getraenke vorhanden.\n"),0;
916
917 fn=old_explode(object_name(ME),"#")[0];
918 printf("\n%'_'|30s %3s %3s %3s %5s %2s %2s %3s %3s %4s %3s\n",
919 "ITEM","ALC","DRI","FOO","VALUE","RT","DL","_HP","_SP","TEST","MAX");
920 for ( --si ; si>=0 ; si-- )
921 {
922 ident=liste[si];
923 minfo=deep_copy(menu_list[ident,PM_INFO]);
924
925 if ( (xinfo=adjust_info(ident,minfo,PL,PL)) && mappingp(xinfo) )
926 minfo+=xinfo;
927
928 minfo[P_VALUE] = eval_anything(minfo[P_VALUE], PL);
929 minfo[P_FOOD] = eval_anything(minfo[P_FOOD], PL);
930 minfo[P_ALCOHOL] = eval_anything(minfo[P_ALCOHOL], PL);
931 minfo[P_DRINK] = eval_anything(minfo[P_DRINK], PL);
932 minfo[PM_DELAY_PUBMASTER]
933 = eval_anything(menu_list[ident,PM_DELAY], PL);
934 minfo[PM_RATE_PUBMASTER]
935 = eval_anything(menu_list[ident,PM_RATE], PL);
936 minfo[P_HP] = eval_anything(minfo[P_HP], PL);
937 minfo[P_SP] = eval_anything(minfo[P_SP], PL);
938 erg=PUBMASTER->RegisterItem(menu_list[ident,0],minfo);
939 max=PUBMASTER->CalcMax(minfo,fn);
940
941 printf("%-'..'30.30s %3d %3d %3d %5d %2d %2d %3d %3d %|4s %3d\n",
942 menu_list[ident,PM_TEXT],
943 minfo[P_ALCOHOL], minfo[P_DRINK], minfo[P_FOOD],
944 minfo[P_VALUE],
945 minfo[PM_RATE_PUBMASTER],
946 minfo[PM_DELAY_PUBMASTER],
947 minfo[P_HP], minfo[P_SP],
948 ( erg ? "OK" : "FAIL" ),max);
949 }
950 write("Done.\n");
951 return 1;
952}
953
954void reset()
955{
956 if ( sum>0 )
957 ZENTRALBANK->PayIn(sum);
958 sum=0;
959 refresh_count++;
960 UpdateAvailability();
961}
962
963void add_gluehwein()
964{
965 if ( ctime(time())[4..6]=="Dec" )
966 AddToMenu( "Gluehwein",({"gluehwein"}),([
967 P_VALUE : 80,
968 P_DRINK : 5,
969 P_ALCOHOL : 20,
970 P_HP : 15,
971 P_SP : 15 ]),2,({
972 ("Du trinkst ein Glas Gluehwein, an dem Du Dir beinahe die Zunge "+
973 "verbrennst.\n"),
974 ("&& bestellt ein Glas Gluehwein und verbrennt sich beim\n"+
975 "Trinken beinahe die Zunge.\n") }), 0, 0, 0);
976}
977
978void add_std_drinks()
979{
980 if ( QueryProp(P_NO_STD_DRINK) )
981 return ;
982 add_gluehwein();
983}
984
985mapping query_menulist()
986{
987 return deep_copy(menu_list);
988}
989
990string *query_drinks()
991{
992 string *dr=({});
993 foreach( string ident, string menuetext, mapping minfo: menu_list) {
994 if (eval_anything(minfo[P_DRINK], 0))
995 dr += ({ ident });
996 }
997 return dr;
998}
999
1000string *query_food()
1001{
1002 string *fo=({});
1003 foreach( string ident, string menuetext, mapping minfo: menu_list) {
1004 if (eval_anything(minfo[P_FOOD], 0))
1005 fo += ({ ident });
1006 }
1007 return fo;
1008}