| // |
| // pub.c -- Alles, was eine Kneipe braucht. |
| // |
| // $Id: pub.c 8778 2014-04-30 23:04:06Z Zesstra $ |
| // spendiere ueberarbeitet, 22.05.2007 - Miril |
| #pragma strong_types |
| #pragma save_types |
| #pragma pedantic |
| #pragma range_check |
| #pragma no_clone |
| |
| #define NEED_PROTOTYPES |
| #include <thing/commands.h> |
| #include <thing/properties.h> |
| |
| #include <defines.h> |
| #include <rooms.h> |
| #include <properties.h> |
| #include <routingd.h> |
| #include <bank.h> |
| #include <exploration.h> |
| #include <wizlevels.h> |
| #include <pub.h> |
| |
| // Alle nicht-privaten werden in erbenen Objekten verwendet. |
| private nosave int max_list; |
| private nosave int refresh_count; |
| private nosave int sum; |
| private nosave mapping refresh_list; |
| nosave mapping id_list; |
| nosave mapping menu_list; |
| nosave object *waiting; |
| |
| #define PM_RATE_PUBMASTER "rate" |
| #define PM_DELAY_PUBMASTER "delay" |
| |
| protected void create() |
| { object router; |
| |
| SetProp( P_ROOM_TYPE, QueryProp(P_ROOM_TYPE) | RT_PUB ); |
| |
| SetProp( P_PUB_NOT_ON_MENU, |
| "Tut mir leid, das fuehren wir nicht! Wir sind ein anstaendiges "+ |
| "Lokal!\n" ); |
| SetProp( P_PUB_UNAVAILABLE, |
| "Davon ist leider nichts mehr da.\n" ); |
| SetProp(P_PUB_NO_MONEY, |
| "Das kostet %d Goldstuecke, und Du hast nicht so viel!\n" ); |
| SetProp(P_PUB_NO_KEEPER, |
| "Es ist niemand anwesend, der Dich bedienen koennte.\n"); |
| |
| AddCmd( "menue","menue" ); |
| AddCmd( ({"kauf","kaufe","bestell","bestelle"}),"bestelle" ); |
| AddCmd( ({"spendier","spendiere"}),"spendiere" ); |
| AddCmd( "pubinit","pubinit" ); |
| |
| max_list=0; |
| refresh_count=0; |
| waiting = ({ }); |
| id_list=([]); |
| menu_list=([]); |
| refresh_list=([]); |
| |
| if ( !clonep(ME) && objectp(router=find_object(ROUTER)) ) |
| router->RegisterTarget(TARGET_PUB,object_name(ME)); |
| |
| call_out("add_std_drinks",1); |
| } |
| |
| protected void create_super() { |
| set_next_reset(-1); |
| } |
| |
| /* Zur Syntax: |
| * |
| * menuetext - Der Text steht im Menue |
| * |
| * ids - Array der Namen, mit denen bestellt werden kann |
| * |
| * minfo - Mapping mit Eintraegen fuer: |
| * P_HP (HP-Heilung), |
| * P_SP (SP-Heilung), |
| * P_FOOD (Saettigung), |
| * P_DRINK (Fluessigkeit) |
| * P_ALCOHOL (Alkoholisierung) |
| * P_VALUE (Preis) |
| * Die Eintraege werden ueber eval_anything ausgewertet |
| * (siehe da) |
| * |
| * rate - Heilrate (auch ueber eavl_anything) in Punkte / heart_beat() |
| * |
| * msg - Meldung beim Essen. |
| * a) closure (wird mit funcall(msg,zahler,empfaenger) |
| * ausgewertet) |
| * b) string (wie closure: call_other(this_object...)) |
| * c) array mit 2 strings: 1) fuer Essenden, 2) fuer andere |
| * siehe auch mess() |
| * |
| * refresh - Mapping mit den moeglichen Eintraegen: |
| * PR_USER : <Kontingent> ; <Update> (pro Spieler) |
| * PR_ALL : <Kontingent> ; <Update> (fuer alle) |
| * Es wird zunaechst geprueft, ob noch etwas fuer den |
| * (zahlenden!) Spieler selbst vorhanden ist wenn nein wird |
| * geschaut, ob das Kontingent fuer alle schon erschoepft ist. |
| * Sind beide Kontingente erschoepft, kann der Spieler das |
| * Bestellte nicht bekommen. |
| * Die Kontingente wird alle <Update> reset()s "aufgefrischt". |
| * <Kontingent> wird ueber eval_anything() ausgewertet. |
| * Alternativ kann man einen Int-Wert angeben. Dieser wird wie |
| * ([ PR_ALL : <wert> ; 1 ]) behandelt. |
| * |
| * delay - Zahl der Sekunden, um die verzoegert die Heilung eintritt |
| * z.B. weil das Essen erst zubereitet werden muss. |
| * Ebenfalls ueber eval_anything() |
| * |
| * d_msg - Meldung beim bestellen, falls Delay. Wie msg. |
| */ |
| varargs string AddToMenu(string menuetext, mixed ids, mapping minfo, |
| mixed rate, mixed msg, mixed refresh, |
| mixed delay, mixed d_msg) |
| { string ident; |
| int i; |
| |
| if ( !stringp(menuetext) || !ids || !mappingp(minfo) ) |
| return 0; |
| |
| if ( stringp(ids) ) |
| ids = ({ ids }); |
| else if ( !pointerp(ids) ) |
| return 0; |
| |
| ident = sprintf("menuentry%d",max_list); |
| max_list++; |
| |
| /* Fuer schnelles Nachschlagen ein eigenes Mapping fuer Ids */ |
| for( i=sizeof(ids)-1;i>=0;i-- ) |
| id_list += ([ ids[i] : ident ]); |
| |
| if ( intp(refresh) && (refresh>0) ) |
| refresh = ([ PR_ALL : refresh; 1 ]); |
| else if ( !mappingp(refresh) ) |
| refresh = 0; |
| |
| menu_list += ([ ident : menuetext; minfo; rate; msg; refresh; |
| delay; d_msg; ids ]); |
| return ident; |
| } |
| |
| // Diese Methode ist nur noch aus Kompatibilitaetsgruenden vorhanden und darf |
| // nicht mehr verwendet werden!!! |
| void AddFood(string nameOfFood, mixed ids, int price, int heal, |
| mixed myFunction) |
| { |
| if ( !nameOfFood || !ids || !price) |
| return; /* Food not healing is ok ! */ |
| |
| AddToMenu( nameOfFood,ids, |
| ([ P_VALUE : price, P_FOOD : heal, P_HP : heal, P_SP : heal ]), |
| ((heal>5)?5:heal), myFunction, 0,0,0); |
| } |
| |
| // Diese Methode ist nur noch aus Kompatibilitaetsgruenden vorhanden und darf |
| // nicht mehr verwendet werden!!! |
| void AddDrink(string nameOfDrink, mixed ids, int price, int heal, |
| int strength, int soak, mixed myFunction) |
| { |
| if ( !nameOfDrink || !ids || !price ) |
| return; |
| |
| heal=heal/2; |
| /* Kleine Korrektur, damit man in alten Pubs ueberhaupt trinken kann */ |
| AddToMenu(nameOfDrink,ids, |
| ([ P_VALUE : price, P_DRINK : soak, P_ALCOHOL : strength, |
| P_HP : heal, P_SP : heal ]), |
| ((heal>5)?5:heal), myFunction,0,0,0); |
| } |
| |
| int RemoveFromMenu(mixed ids) { |
| int ret; |
| |
| if (stringp(ids)) |
| ids = ({ids}); |
| |
| if (pointerp(ids)) { |
| foreach (string id: ids) { |
| // look if the id has a matching ident |
| string ident = id_list[id]; |
| if (stringp(ident)) { |
| // remove this ident-entry from the id-list ... |
| m_delete(id_list, id); |
| // ... and remove all others now too (so it won't bug later, if |
| // the wizard calling this method forgot an id) |
| foreach (string listid: m_indices(id_list)) |
| if (id_list[listid] == ident) |
| m_delete(id_list, listid); |
| |
| // now remove the ident from the menu_list |
| if (member(menu_list, ident)) { |
| ret++; |
| m_delete(menu_list, ident); |
| |
| // decrease the ident-counter, if this entry was the last one |
| int oldnum; |
| if (sscanf(ident, "menuentry%d", oldnum) == 1 && |
| oldnum == (max_list-1)) |
| max_list--; |
| } |
| } |
| } |
| } |
| // return removed entries |
| return ret; |
| } |
| |
| /* Zum Auswerten der Eintraege fuer Preis, Rate, HP... |
| * a) integer-Wert -> wird direkt uebernommen |
| * b) mapping -> Wird als RaceModifiere verstanden. Es wird der |
| * Eintrag gewaehlt, der der Rasse des Spielers |
| * entspricht, falls vorhanden, ansonsten der Eintrag |
| * fuer 0. |
| * c) Array -> In erstem Element (muss Objekt oder dessen Filename |
| * sein) wird die Funktion mit dem Namen im 2.Element |
| * aufgerufen. |
| * d) String -> Die genannte Funktion wird in der Kneipe selbst |
| * aufgerufen. |
| * e) Closure -> Die Closure wird ausgewertet. |
| * Alle Funktionsaufrufe bekommen den essenden Spieler (bei Price und Delay |
| * den bestellenden Spieler) als Argument uebergeben. Die Auswertung erfolgt |
| * in der angegebenen Reihenfolge. Am Ende muss ein Intergerwert herauskommen |
| */ |
| int eval_anything(mixed what, object pl) |
| { mixed re; |
| |
| if (intp(what)) |
| return what; |
| |
| if (mappingp(what) && pl) |
| { |
| re = what[pl->QueryProp(P_RACE)]||what[0]; |
| } |
| |
| if (re) |
| what=re; |
| |
| if ( pointerp(what) && (sizeof(what)>=2) |
| && ( objectp(what[0]) || stringp(what[0]) ) |
| && stringp(what[1]) ) |
| what = call_other(what[0],what[1],pl); |
| |
| if ( stringp(what) && function_exists(what,ME) ) |
| what = call_other(ME,what,pl); |
| |
| if ( closurep(what) ) |
| what = funcall(what,pl); |
| |
| if ( intp(what) ) |
| return what; |
| |
| return 0; |
| } |
| |
| /* Diese Funktion ueberprueft, ob das Kontingent eines Menueeintrags |
| * fuer einen Spieler erschoepft ist. |
| */ |
| string CheckAvailability(string ident, object zahler) |
| { string uid; |
| |
| if ( !stringp(ident) || !member(menu_list,ident) || !objectp(zahler) ) |
| return 0; |
| if ( !mappingp(menu_list[ident,PM_REFRESH]) ) |
| return PR_NONE; |
| |
| if ( !member(refresh_list,ident) ) |
| refresh_list += ([ ident : ([ ]) ]); |
| |
| if ( query_once_interactive(zahler) ) |
| uid=getuid(zahler); |
| else |
| uid=object_name(zahler); |
| |
| if ( member(menu_list[ident,PM_REFRESH],PR_USER) ) |
| { |
| if ( !member(refresh_list[ident],uid) ) |
| { |
| refresh_list[ident] += ([ uid : 0 ; refresh_count ]); |
| } |
| |
| /* Kontingent des Zahlenden pruefen */ |
| if ( refresh_list[ident][uid,PRV_AMOUNT] < |
| eval_anything(menu_list[ident,PM_REFRESH][PR_USER,PRV_AMOUNT], |
| zahler) ) |
| return uid; |
| } |
| |
| if ( member(menu_list[ident,PM_REFRESH],PR_ALL) ) |
| { |
| if ( !member(refresh_list[ident],PR_DEFAULT) ) |
| { |
| refresh_list[ident] += ([ PR_DEFAULT : 0 ; refresh_count ]); |
| } |
| |
| /* Kontingent der Allgemeinheit pruefen */ |
| if ( refresh_list[ident][PR_DEFAULT,PRV_AMOUNT] < |
| eval_anything(menu_list[ident,PM_REFRESH][PR_ALL,PRV_AMOUNT], |
| zahler) ) |
| return PR_DEFAULT; |
| } |
| |
| return 0; |
| } |
| |
| /* Diese Funktion reduziert das Kontingent des Lebewesens uid beim |
| * Menueeintrag ident um 1 |
| */ |
| void DecreaseAvailability(string ident, string uid) |
| { |
| if ( !stringp(ident) || !stringp(uid) ) |
| return; |
| refresh_list[ident][uid,PRV_AMOUNT]++; |
| } |
| |
| /* Diese Funktion sorgt dafuer, dass die Kontingente an limitierten |
| * Sachen in regelmaessigen Abstaenden wiederhergestellt werden. |
| */ |
| static void UpdateAvailability() |
| { int i1,i2; |
| string *ind1,*ind2,chk; |
| |
| /* Keine Refresh-Eintraege, kein Update */ |
| if ( !mappingp(refresh_list) |
| || (i1=sizeof(ind1=m_indices(refresh_list)))<1 ) |
| return; |
| |
| /* Es muss jeder Menueeintrag, der in der refresh_list steht, |
| * durchgegangen werden. |
| */ |
| for ( --i1 ; i1>=0 ; i1-- ) |
| { |
| if ( !mappingp(refresh_list[ind1[i1]]) |
| || (i2=sizeof(ind2=m_indices(refresh_list[ind1[i1]])))<1 ) |
| continue; |
| |
| /* Fuer jeden Menueeintrag muss jeder Spielereintrag durchgegangen |
| * werden, der in dem entspr. mapping steht. |
| */ |
| for ( --i2 ; i2>=0 ; i2-- ) // Alle Spieler |
| { |
| if ( ind2[i2]==PR_DEFAULT ) |
| chk = PR_ALL; |
| else |
| chk = PR_USER; |
| |
| if ( ( refresh_list[ind1[i1]][ind2[i2],PRV_REFRESH] |
| + menu_list[ind1[i1],PM_REFRESH][chk,PRV_REFRESH] ) |
| <= refresh_count ) |
| { |
| refresh_list[ind1[i1]][ind2[i2],PRV_AMOUNT]=0; |
| refresh_list[ind1[i1]][ind2[i2],PRV_REFRESH]=refresh_count; |
| } |
| } |
| } |
| } |
| |
| mixed DBG(mixed o) { |
| if(find_player("rumata")) |
| tell_object( |
| find_player("rumata"), |
| sprintf("DBG: %O\n", o) |
| ); |
| return 0; |
| } |
| |
| /* Erweitert um die Moeglichkeit, Speise- oder Getraenke-Karte zu sehen. */ |
| string menue_text(string str) |
| { int i,sdr,sfo; |
| string ident,res; |
| string *fo=({}),*dr=({}); |
| |
| if ( !max_list ) |
| return "Hier scheint es derzeit nichts zu geben.\n"; |
| |
| if ( !stringp(str) || str=="" ) |
| str="alles"; |
| |
| /* Fuers Menue entscheiden ob Drink oder Food */ |
| foreach(string id, string menuetext, mapping minfo: menu_list) |
| { |
| if (eval_anything(minfo[P_FOOD],this_player())) |
| fo+=({ id }); |
| else |
| dr+=({ id }); |
| } |
| |
| sdr = sizeof(dr); |
| sfo = sizeof(fo); |
| |
| if ( member(({"alle","alles"}),str)!=-1) |
| { |
| if ( !sfo ) |
| str="drinks"; |
| else if ( !sdr ) |
| str="speise"; |
| else |
| { |
| /* Gemischte Karte */ |
| res = "Getraenke Preis alc | "+ |
| "Speisen Preis\n"+ |
| "---------------------------------------+-"+ |
| "--------------------------------------\n"; |
| |
| for ( i=0 ; ( i<sdr || i<sfo ) ; i++ ) |
| { |
| if ( i<sdr ) |
| res += sprintf("%-29.29s%5.5d %c | ", |
| menu_list[dr[i],PM_TEXT], |
| eval_anything(menu_list[dr[i],PM_INFO][P_VALUE],PL), |
| (eval_anything(menu_list[dr[i],PM_INFO][P_ALCOHOL],PL)>0) ? 'J' : 'N'); |
| else |
| res += " | "; |
| |
| if ( i<sfo ) |
| res += sprintf("%-33.33s%5.5d", |
| menu_list[fo[i],PM_TEXT], |
| eval_anything(menu_list[fo[i],PM_INFO][P_VALUE],PL)); |
| |
| res += "\n"; |
| } |
| |
| return res; |
| } |
| } |
| |
| /* Reine Getraenkekarte */ |
| if ( member(({"getraenke","drinks","getraenk","trinken"}),str)!=-1 ) |
| { |
| if ( !sdr ) |
| return "Hier gibt es leider nichts zu trinken.\n"; |
| |
| res = "Getraenke Preis alc | "+ |
| "Getraenke Preis alc\n"+ |
| "---------------------------------------+-"+ |
| "--------------------------------------\n"; |
| |
| for ( i=0 ; i<sdr ; i++ ) |
| { |
| ident = dr[i]; |
| |
| if ( !eval_anything(menu_list[ident,PM_INFO][P_FOOD], PL) ) |
| res += sprintf("%-29.29s%5.5d %c%s", |
| menu_list[ident,PM_TEXT], |
| eval_anything(menu_list[ident,PM_INFO][P_VALUE],PL), |
| (eval_anything(menu_list[ident,PM_INFO][P_ALCOHOL],PL)>0) ? 'J' : 'N', |
| ((i%2)?"\n":" | ")); |
| } |
| |
| if ( res[<1..<1]!="\n" ) |
| res += "\n"; |
| |
| return res; |
| } |
| |
| /* Reine Speisekarte */ |
| if ( member(({"speise","speisen","essen"}),str)!=-1 ) |
| { |
| if ( !sfo ) |
| return "Hier gibt es leider nichts zu essen.\n"; |
| |
| res = "Speisen Preis | "+ |
| "Speisen Preis\n"+ |
| "---------------------------------------+-"+ |
| "--------------------------------------\n"; |
| |
| for ( i=0 ; i<sfo ; i++ ) |
| { |
| ident = fo[i]; |
| if (eval_anything(menu_list[ident,PM_INFO][P_FOOD],PL) ) |
| res += sprintf("%-33.33s%5.5d%s", |
| menu_list[ident,PM_TEXT], |
| eval_anything(menu_list[ident,PM_INFO][P_VALUE],PL), |
| ((i%2)?"\n":" | ")); |
| } |
| |
| if ( res[<1..<1]!="\n" ) |
| res += "\n"; |
| |
| return res; |
| } |
| |
| return 0; |
| } |
| |
| int menue(string str) |
| { string txt; |
| |
| _notify_fail("Welchen Teil des Menues moechtest Du sehen?\n"); |
| if ( !stringp(txt=menue_text(str)) || sizeof(txt)<1 ) |
| return 0; |
| write(txt); |
| return 1; |
| } |
| |
| /* Diese Funktion kann/soll bei Bedarf ueberladen werden, um simultane |
| * Aenderungen des Mappings zu ermoeglichen (zu Beispiel wie es in guten |
| * Tagen groesser Portionen gib, Hobbits per se mehr kriegen, ... |
| */ |
| mapping adjust_info(string ident, mapping minfo, object zahler, |
| object empfaenger) |
| { |
| return 0; |
| } |
| |
| /* Hier hats jede Menge neue Platzhalter */ |
| string mess(string str,object pl) |
| { |
| string dummy1, dummy2; |
| |
| if ( !pl ) |
| pl=PL; |
| |
| if ( !stringp(str) || str=="" ) |
| return str; |
| |
| str=implode(explode(str,"&&"),pl->name(WER,2)); |
| str=implode(explode(str,"&1&"),pl->name(WER,2)); |
| str=implode(explode(str,"&2&"),pl->name(WESSEN,2)); |
| str=implode(explode(str,"&3&"),pl->name(WEM,2)); |
| str=implode(explode(str,"&4&"),pl->name(WEN,2)); |
| str=implode(explode(str,"&1#"),capitalize(pl->name(WER,2))); |
| str=implode(explode(str,"&2#"),capitalize(pl->name(WESSEN,2))); |
| str=implode(explode(str,"&3#"),capitalize(pl->name(WEM,2))); |
| str=implode(explode(str,"&4#"),capitalize(pl->name(WEN,2))); |
| str=implode(explode(str,"&!"),pl->QueryPronoun(WER)); |
| str=implode(explode(str,"&5&"),pl->QueryPronoun(WER)); |
| str=implode(explode(str,"&6&"),pl->QueryPronoun(WESSEN)); |
| str=implode(explode(str,"&7&"),pl->QueryPronoun(WEM)); |
| str=implode(explode(str,"&8&"),pl->QueryPronoun(WEN)); |
| str=implode(explode(str,"&5#"),capitalize(pl->QueryPronoun(WER))); |
| str=implode(explode(str,"&6#"),capitalize(pl->QueryPronoun(WESSEN))); |
| str=implode(explode(str,"&7#"),capitalize(pl->QueryPronoun(WEM))); |
| str=implode(explode(str,"&8#"),capitalize(pl->QueryPronoun(WEN))); |
| |
| return break_string(capitalize(str),78,"", BS_LEAVE_MY_LFS); |
| } |
| |
| protected void _copy_menulist_values(mapping entryinfo, string ident) { |
| /* Kopieren aller Werte ins minfo-Mapping, um Problemen bei Loeschung |
| aus dem Weg zu gehen. Slow and dirty */ |
| entryinfo[PM_TEXT] = deep_copy(menu_list[ident, PM_TEXT]); |
| // PM_INFO is already flat in entryinfo |
| entryinfo[PM_RATE_PUBMASTER] |
| = deep_copy(menu_list[ident, PM_RATE]); |
| entryinfo[PM_SERVE_MSG] = deep_copy(menu_list[ident, PM_SERVE_MSG]); |
| entryinfo[PM_REFRESH] = deep_copy(menu_list[ident, PM_REFRESH]); |
| // PM_DELAY is already evaluated in entryinfo |
| entryinfo[PM_DELAY_MSG] = deep_copy(menu_list[ident, PM_DELAY_MSG]); |
| entryinfo[PM_IDS] = deep_copy(menu_list[ident, PM_IDS]); |
| } |
| |
| int do_deliver(string ident, object zahler, object empfaenger, |
| mapping entryinfo) { |
| waiting -= ({ empfaenger,0 }); |
| |
| /* Empfaenger muss natuerlich noch da sein */ |
| if ( !objectp(empfaenger) || !present(empfaenger) ) |
| return 0; |
| |
| /* Zahler wird nur wegen der Abwaertskompatibilitaet gebraucht */ |
| if ( !objectp(zahler) ) |
| zahler = empfaenger; |
| |
| // alte Pubs, die do_deliver irgendwie selbst aufrufen, sollten |
| // mit der Zeit korrigiert werden |
| if(!mappingp(entryinfo)) |
| raise_error("Pub ruft do_deliver() ohne sinnvolle Argumente auf.\n"); |
| if(!member(entryinfo, PM_RATE_PUBMASTER)) { |
| if(!member(menu_list, ident)) |
| raise_error("Pub ruft do_deliver() mit geloeschtem Getraenk und " |
| "teilweisen Argumenten auf!\n"); |
| |
| _copy_menulist_values(entryinfo, ident); |
| call_out(#'raise_error, 1, |
| "Pub ruft do_deliver() nur mit teilweisen Argumenten auf.\n"); |
| } |
| |
| entryinfo[PM_RATE_PUBMASTER] = eval_anything(entryinfo[PM_RATE_PUBMASTER], |
| empfaenger); |
| entryinfo[P_HP] = eval_anything(entryinfo[P_HP], empfaenger); |
| entryinfo[P_SP] = eval_anything(entryinfo[P_SP], empfaenger); |
| |
| /* Ueberpruefen, ob Heilmoeglichkeit legal */ |
| if ( query_once_interactive(empfaenger) |
| && ((PUBMASTER->RegisterItem(entryinfo[PM_TEXT], entryinfo))<1) ) { |
| tell_object(empfaenger, |
| "Mit diesem Getraenk/Gericht scheint etwas nicht in Ordnung "+ |
| "zu sein.\nVerstaendige bitte den Magier, der fuer diesen "+ |
| "Raum verantwortlich ist.\n"); |
| return -4; |
| } |
| |
| if ( QueryProp(P_NPC_FASTHEAL) && !query_once_interactive(empfaenger) ) { |
| entryinfo[H_DISTRIBUTION] = HD_INSTANT; |
| } |
| else { |
| entryinfo[H_DISTRIBUTION] = entryinfo[PM_RATE_PUBMASTER]; |
| } |
| empfaenger->consume(entryinfo); |
| |
| /* Meldung ausgeben */ |
| /* Hinweis: Da die ausfuehrenden Funktionen auch ident und minfo |
| * uebergeben bekommen, kann man hier auch ueber adjust_info oder |
| * an anderer Stelle zusaetzliche Informationen uebergeben... |
| */ |
| if (closurep(entryinfo[PM_SERVE_MSG]) ) |
| funcall(entryinfo[PM_SERVE_MSG], zahler, empfaenger, ident, entryinfo); |
| else if (stringp(entryinfo[PM_SERVE_MSG]) && |
| function_exists(entryinfo[PM_SERVE_MSG],ME)) |
| call_other(ME, entryinfo[PM_SERVE_MSG], zahler, empfaenger, ident, |
| entryinfo); |
| else if (pointerp(entryinfo[PM_SERVE_MSG]) && |
| sizeof(entryinfo[PM_SERVE_MSG])>=2) { |
| if (stringp(entryinfo[PM_SERVE_MSG][0]) && |
| sizeof(entryinfo[PM_SERVE_MSG][0])) |
| tell_object(empfaenger, |
| mess(entryinfo[PM_SERVE_MSG][0]+"\n", empfaenger)); |
| if (stringp(entryinfo[PM_SERVE_MSG][1]) && |
| sizeof(entryinfo[PM_SERVE_MSG][1])) |
| tell_room(environment(empfaenger)||ME, |
| mess(entryinfo[PM_SERVE_MSG][1]+"\n",empfaenger), |
| ({empfaenger}) ); |
| } |
| |
| return 1; |
| } |
| |
| /* Testet, ob genug Geld zur Verfuegung steht. |
| * Falls die Bonitaet anderen Beschraenkungen unterliegt, als |
| * dass der Zahler genug Geld dabei hat, muss diese Methode |
| * ueberschrieben werden. |
| * Rueckgabewerte: |
| * -2 : Out of Money |
| * 0 : Alles OK. |
| * Rueckgabewerte != 0 fuehren zu einem Abbruch der Bestellung |
| */ |
| int CheckSolvency(string ident, object zahler, object empfaenger, |
| mapping entryinfo) |
| { |
| if ( (zahler->QueryMoney())<entryinfo[P_VALUE] ) |
| { |
| string res; |
| if ( !stringp(res=QueryProp(P_PUB_NO_MONEY)) ) |
| res = "Das kostet %d Goldstuecke, und Du hast nicht so viel!\n"; |
| tell_object(zahler,sprintf(res, entryinfo[P_VALUE])); |
| return -2; |
| } |
| return 0; |
| } |
| |
| /* Fuehrt die Bezahlung durch. |
| * Falls die Bezahlung anders erfolgt, als durch Abzug des Geldes vom Zahler, |
| * muss diese Methode ueberschrieben werden |
| * Rueckgabewerte: |
| * Anzahl der Muenzen, die im Pub landen und bei Reset in die Zentralbank |
| * eingezahlt werden |
| */ |
| int DoPay(string ident, object zahler, object empfaenger, mapping entryinfo) |
| { |
| zahler->AddMoney(-entryinfo[P_VALUE]); |
| return entryinfo[P_VALUE]; |
| } |
| |
| /* Rueckgabewerte: |
| * -6 : Nicht vorraetig |
| * -5 : Wirt nicht anwesend |
| * -4 : Illegales Getraenk/Gericht. Ausgabe verweigert. |
| * Nur bei sofortiger Lieferung... |
| * -3 : Empfaenger bereits voll |
| * -2 : Out of Money |
| * -1 : spendieren ignoriert |
| * 0 : Empfaenger ausgeflogen (sollte eigentlich nicht passieren) |
| * 1 : Alles OK. |
| */ |
| int consume_something(string ident, object zahler, object empfaenger) { |
| if ( !objectp(zahler) ) |
| zahler=PL; |
| |
| if ( !objectp(empfaenger) ) |
| empfaenger=PL; |
| |
| /* Die Abfrage auf anwesenden Wirt erfolgt NUR an dieser Stelle, damit */ |
| /* kein Spieler darunter leiden muss, wenn jemand anderes zwischen */ |
| /* Bestellung und Lieferung den Wirt meuchelt. */ |
| if ( stringp(QueryProp(P_KEEPER)) && !present(QueryProp(P_KEEPER), ME)) |
| { |
| string res = QueryProp(P_PUB_NO_KEEPER); |
| if ( !stringp(res) ) { |
| res = "Es ist niemand anwesend, der Dich bedienen koennte.\n"; |
| } |
| tell_object(zahler,res); |
| return -5; |
| } |
| |
| /* Spendiert und ignoriert? */ |
| if ( zahler!=empfaenger ) |
| { |
| mixed res = ({"spendiere"}); |
| if ( eval_anything(menu_list[ident,PM_INFO][P_DRINK],empfaenger) ) |
| res += ({"spendiere.getraenke"}); |
| if ( eval_anything(menu_list[ident,PM_INFO][P_FOOD],empfaenger) ) |
| res += ({"spendiere.essen"}); |
| if ( eval_anything(menu_list[ident,PM_INFO][P_ALCOHOL],empfaenger) ) |
| res += ({"spendiere.alkohol"}); |
| if ( empfaenger->TestIgnoreSimple(res) ) |
| { |
| tell_object(zahler, |
| empfaenger->Name(WER)+" will das nicht.\n"); |
| return -1; |
| } |
| } |
| |
| /* Hier kann das Info-Mapping erst mal als ganzes angepasst werden. */ |
| mapping xinfo; |
| mapping entryinfo = deep_copy(menu_list[ident, PM_INFO]); |
| if ( (xinfo=adjust_info(ident,entryinfo,zahler,empfaenger)) && |
| mappingp(xinfo) ) |
| entryinfo += xinfo; |
| |
| /* Genug Geld vorhanden? */ |
| entryinfo[P_VALUE] = eval_anything(entryinfo[P_VALUE], zahler); |
| { |
| int res = CheckSolvency(ident, zahler, empfaenger, entryinfo); |
| if (res != 0) return res; |
| } |
| |
| string avb; |
| if ( !stringp(avb=CheckAvailability(ident, zahler)) ) |
| { |
| string res = QueryProp(P_PUB_UNAVAILABLE); |
| if ( !stringp(res) ) |
| res = "Davon ist leider nichts mehr da.\n"; |
| tell_object(zahler,res); |
| return -6; |
| } |
| |
| /* Textausgabe beim spendieren */ |
| if ( empfaenger!=zahler) |
| { |
| tell_room(environment(empfaenger)||ME, |
| zahler->Name(WER)+" spendiert "+empfaenger->name(WEM)+" etwas.\n", |
| ({zahler, empfaenger}) ); |
| tell_object(empfaenger, |
| zahler->Name(WER)+" spendiert Dir etwas.\n"); |
| tell_object(zahler, |
| "Du spendierst "+empfaenger->name(WEM)+" etwas.\n"); |
| } |
| |
| /* Testen, ob mans noch essen / trinken kann */ |
| /* Die int-Werte werden in minfo uebernommen fuer die Auswertung */ |
| /* im Pubmaster. */ |
| entryinfo[P_FOOD] = eval_anything(entryinfo[P_FOOD], empfaenger); |
| entryinfo[P_ALCOHOL] = eval_anything(entryinfo[P_ALCOHOL],empfaenger); |
| entryinfo[P_DRINK] = eval_anything(entryinfo[P_DRINK], empfaenger); |
| |
| int result = empfaenger->consume(entryinfo, 1); |
| if (result < 0) { |
| if (result & HC_MAX_FOOD_REACHED) |
| tell_object(empfaenger, |
| "Du bist zu satt, das schaffst Du nicht mehr.\n"); |
| else if (result & HC_MAX_DRINK_REACHED) |
| tell_object(empfaenger, |
| "So viel kannst Du im Moment nicht trinken.\n"); |
| else if (result & HC_MAX_ALCOHOL_REACHED) |
| tell_object(empfaenger, |
| "Soviel Alkohol vertraegst Du nicht mehr.\n"); |
| return -3; |
| } |
| |
| /* Gezahlt wird auch sofort */ |
| sum += DoPay(ident, zahler, empfaenger, entryinfo); |
| |
| /* FPs gibts auch sofort */ |
| if (zahler == empfaenger) |
| GiveEP(EP_PUB,menu_list[ident,PM_IDS][0]); |
| |
| /* Falls die Anzahl des Bestellten beschraenkt ist, muss diese natuerlich |
| * angepasst werden. |
| */ |
| if ( avb!=PR_NONE ) |
| DecreaseAvailability(ident,avb); |
| |
| /* Gibt es eine Zeitverzoegerung zwischen Bestellen und Servieren? */ |
| entryinfo[PM_DELAY_PUBMASTER] = eval_anything(menu_list[ident, PM_DELAY], zahler); |
| |
| // alle fuer einen Drink notwendigen Werte kopieren |
| _copy_menulist_values(entryinfo, ident); |
| |
| if (entryinfo[PM_DELAY_PUBMASTER]<=0) |
| return do_deliver(ident,zahler,empfaenger,entryinfo); |
| |
| /* Bestell-Meldung ausgeben */ |
| if (closurep(entryinfo[PM_DELAY_MSG])) |
| funcall(entryinfo[PM_DELAY_MSG], zahler, empfaenger,ident, entryinfo); |
| else if (stringp(entryinfo[PM_DELAY_MSG]) && |
| function_exists(entryinfo[PM_DELAY_MSG],ME)) |
| call_other(ME, entryinfo[PM_DELAY_MSG], zahler, empfaenger, ident, |
| entryinfo); |
| else if (pointerp(entryinfo[PM_DELAY_MSG]) && |
| sizeof(entryinfo[PM_DELAY_MSG])>=2) { |
| if (stringp(entryinfo[PM_DELAY_MSG][0]) && |
| sizeof(entryinfo[PM_DELAY_MSG][0])) |
| tell_object(empfaenger, |
| mess(entryinfo[PM_DELAY_MSG][0]+"\n",empfaenger)); |
| if (stringp(entryinfo[PM_DELAY_MSG][1]) && |
| sizeof(entryinfo[PM_DELAY_MSG][1])) |
| tell_room(environment(empfaenger)||ME, |
| mess(entryinfo[PM_DELAY_MSG][1]+"\n",empfaenger), |
| ({empfaenger}) ); |
| } |
| |
| waiting += ({ empfaenger }); |
| call_out("do_deliver", entryinfo[PM_DELAY_PUBMASTER], |
| ident, zahler, empfaenger, entryinfo); |
| |
| return 1; |
| } |
| |
| /* Rueckgabewere: 0: Nicht im Menue gefunde, 1 sonst */ |
| int search_what(string str,object zahler,object empfaenger) |
| { string ident; |
| |
| if ( member(waiting,empfaenger)!=-1 ) |
| { |
| if ( PL==empfaenger ) |
| write("Du wartest doch noch auf etwas!\n"); |
| else |
| write(empfaenger->Name(WER,2)+" wartet noch auf etwas.\n"); |
| return 1; |
| } |
| |
| str = lower_case(str); |
| if ( ident=id_list[str] ) |
| { |
| consume_something(ident,zahler,empfaenger); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| // Neue Version von Mesi: |
| int spendiere(string str) |
| { |
| _notify_fail("spendiere <spieler> <drink>\n"); |
| |
| if ( !stringp(str) || str=="" ) |
| return 0; |
| |
| string who,what; |
| int whoidx; |
| |
| if (sscanf(str,"%s %d %s",who,whoidx,what)!=3 |
| && sscanf(str,"%s %s",who,what)!=2) |
| return 0; |
| object target=present(who, whoidx); |
| if(!target && this_player()) target=present(who, whoidx, this_player()); |
| if ( !target || !living(target) ) |
| { |
| write("Das Lebewesen ist nicht hier...\n"); |
| return 1; |
| } |
| |
| notify_fail((string)QueryProp(P_PUB_NOT_ON_MENU)||"So etwas gibt es hier nicht!\n"); |
| |
| return search_what(what,PL,target); |
| } |
| |
| int bestelle(string str) |
| { |
| notify_fail((string)QueryProp(P_PUB_NOT_ON_MENU)); |
| |
| if ( !stringp(str) ) |
| return 0; |
| |
| return search_what(str,PL,PL); |
| } |
| |
| int pubinit() |
| { string *liste,ident,fn; |
| int si,erg,max; |
| mapping minfo,xinfo; |
| |
| if ( !PL || !IS_WIZARD(PL) ) |
| return 0; |
| |
| si=sizeof(liste=sort_array(m_indices(menu_list),#'<)); |
| if ( si<1 ) |
| return notify_fail("Keine Gerichte/Getraenke vorhanden.\n"),0; |
| |
| fn=old_explode(object_name(ME),"#")[0]; |
| printf("\n%'_'|30s %3s %3s %3s %5s %2s %2s %3s %3s %4s %3s\n", |
| "ITEM","ALC","DRI","FOO","VALUE","RT","DL","_HP","_SP","TEST","MAX"); |
| for ( --si ; si>=0 ; si-- ) |
| { |
| ident=liste[si]; |
| minfo=deep_copy(menu_list[ident,PM_INFO]); |
| |
| if ( (xinfo=adjust_info(ident,minfo,PL,PL)) && mappingp(xinfo) ) |
| minfo+=xinfo; |
| |
| minfo[P_VALUE] = eval_anything(minfo[P_VALUE], PL); |
| minfo[P_FOOD] = eval_anything(minfo[P_FOOD], PL); |
| minfo[P_ALCOHOL] = eval_anything(minfo[P_ALCOHOL], PL); |
| minfo[P_DRINK] = eval_anything(minfo[P_DRINK], PL); |
| minfo[PM_DELAY_PUBMASTER] |
| = eval_anything(menu_list[ident,PM_DELAY], PL); |
| minfo[PM_RATE_PUBMASTER] |
| = eval_anything(menu_list[ident,PM_RATE], PL); |
| minfo[P_HP] = eval_anything(minfo[P_HP], PL); |
| minfo[P_SP] = eval_anything(minfo[P_SP], PL); |
| erg=PUBMASTER->RegisterItem(menu_list[ident,0],minfo); |
| max=PUBMASTER->CalcMax(minfo,fn); |
| |
| printf("%-'..'30.30s %3d %3d %3d %5d %2d %2d %3d %3d %|4s %3d\n", |
| menu_list[ident,PM_TEXT], |
| minfo[P_ALCOHOL], minfo[P_DRINK], minfo[P_FOOD], |
| minfo[P_VALUE], |
| minfo[PM_RATE_PUBMASTER], |
| minfo[PM_DELAY_PUBMASTER], |
| minfo[P_HP], minfo[P_SP], |
| ( erg ? "OK" : "FAIL" ),max); |
| } |
| write("Done.\n"); |
| return 1; |
| } |
| |
| void reset() |
| { |
| if ( sum>0 ) |
| ZENTRALBANK->PayIn(sum); |
| sum=0; |
| refresh_count++; |
| UpdateAvailability(); |
| } |
| |
| void add_gluehwein() |
| { |
| if ( ctime(time())[4..6]=="Dec" ) |
| AddToMenu( "Gluehwein",({"gluehwein"}),([ |
| P_VALUE : 80, |
| P_DRINK : 5, |
| P_ALCOHOL : 20, |
| P_HP : 15, |
| P_SP : 15 ]),2,({ |
| ("Du trinkst ein Glas Gluehwein, an dem Du Dir beinahe die Zunge "+ |
| "verbrennst.\n"), |
| ("&& bestellt ein Glas Gluehwein und verbrennt sich beim\n"+ |
| "Trinken beinahe die Zunge.\n") }), 0, 0, 0); |
| } |
| |
| void add_std_drinks() |
| { |
| if ( QueryProp(P_NO_STD_DRINK) ) |
| return ; |
| add_gluehwein(); |
| } |
| |
| mapping query_menulist() |
| { |
| return deep_copy(menu_list); |
| } |
| |
| string *query_drinks() |
| { |
| string *dr=({}); |
| foreach( string ident, string menuetext, mapping minfo: menu_list) { |
| if (eval_anything(minfo[P_DRINK], 0)) |
| dr += ({ ident }); |
| } |
| return dr; |
| } |
| |
| string *query_food() |
| { |
| string *fo=({}); |
| foreach( string ident, string menuetext, mapping minfo: menu_list) { |
| if (eval_anything(minfo[P_FOOD], 0)) |
| fo += ({ ident }); |
| } |
| return fo; |
| } |