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