// mobiler Händler,
// -----------------
// der herumläuft und u.a. Weintrauben verkauft
//
// Dieser Händler ist schon ein etwas komplexerer NPC. Bitte zuerst
// die beiden Bsp.-Hasen und den Hund anschauen für das Verständnis von
// netten und herumlaufenden NPCs. Außerdem bitte die Beispiele der Rubrik
// Lcontainer anschauen für das Verständnis des Flaschenfüllens.
// Original by Sunrise@Wunderland 2000
//
// Bemerkung: Von allem überflüssigen entschlackt für die Beispielsammlung
// (d.h. kaum noch Infos/Details - es geht um die Funktionalität)
//
// 10.10.2005 Holger: angepasst fuer einheitlichen Coinmaster
#pragma strong_types
inherit "npc";
inherit "trade"; // erbt Hilfsfunktionen fuer Händler
#include <properties.h> // für die allgemeinen Properties
#include <defines.h> // ein paar praktische Defines wg. der Schreibarbeit ;-)
#include <npc/react.h> // es ist ein netter NPC
#include <moving.h> // es ist ein moving NPC
#include <npc/walking.h>
#include <lcontainer.h> // für das Auffüllen der Flaschen
#include <bank.h> // für die Zentralbank
int kaufe(string str); // die Verkaufsabwicklung
string auffuellen(); // der Händler füllt Flaschen (Lcontainer)
// mit Wasser
string preise(); // für die Preisinformationen
void create()
{
if (!clonep()) return;
::create();
SetStandardReactions(); // Nettireaktionen
SetProp(P_NAME_ADJ, "gerissen");
SetProp(P_NAME, "Haendler");
SetProp(P_PLURAL, "Haendler");
SetProp(P_MNPC_HOME, "/doc/beispiele/raum1");
SetProp(P_MNPC_AREA, ({ "/doc/beispiele/" }));
SetProp(P_MNPC_DELAY, 40);
SetProp(P_MMSGOUT, "zieht sein Maultier hinter sich her und verschwindet");
SetProp(P_MSGOUT, "zieht sein Maultier hinter sich her und verschwindet");
SetProp(P_MMSGIN, "kommt mit seinem Maultier herein");
SetProp(P_MSGIN, "kommt mit seinem Maultier herein");
SetProp(P_MNPC_FLAGS, MNPC_WALK);
SetProp(P_GENDER, MALE);
SetProp(P_ALIGN, -200);
SetProp(P_LOG_INFO, "/doc/beispiele/haendler.rep");
// Im Wunderland gibt es verschiedene Währungen.
// Dieser Händler will unbedingt die Außenweltwährung.
SetProp(P_CURRENCY, CT_AUSSENWELT);
// Wenn der Händler stirbt, erzählen wir, daß auch sein Maultier wegrennt.
SetProp(P_DIE_MSG, " faellt tot zu Boden.\n"
"Das Maultier rennt voller Panik davon und ward nie mehr gesehen.\n");
AddId(({"haendler", "mann"}), ({"haendler", "maenner"}));
SetProp(P_ADJECTIVES, ({"gerissen", "gerissener", "gerissenen",
"gerissenem", "gerissene"}));
// Für die Werte für P_BODY etc. machen wirs uns leicht
create_default_npc(25);
////// DETAILS ///////////////////////////////////////////////////////////
SetProp(P_LONG,
"Dieser Haendler ist staendig unterwegs, immer "
"auf der Suche nach einem guten Geschaeft. Er fuehrt ein vollbepacktes "
"Maultier an der Leine hinter sich her.\n"
"Seine gierigen Augen schauen Dich abschaetzend an.");
AddDetail(({"schild", "preise"}), #'preise);
AddReadDetail(({"schild", "preise"}), #'preise);
////// FUNKTIONEN ////////////////////////////////////////////////////////
AddCmd("kauf|kaufe", #'kaufe);
////// INFOS /////////////////////////////////////////////////////////////
AddInfo("fuellst|fuellen|auffuellen&flasche|flaschen", #'auffuellen);
////// REAKTIONEN ////////////////////////////////////////////////////////
// Durch SetStandardReactions() werden ein paar Reaktionen angelegt, die
// nicht so recht zu diesem Händler passen. Wir entfernen sie und deklarieren
// dann neue.
RemoveReaction("danke", R_ME);
RemoveReaction("grinse", R_ME);
RemoveReaction("strecke", R_ME);
RemoveReaction("liebe", R_OTHER);
RemoveReaction("druecke", R_ME);
RemoveReaction("nicke", R_ME);
RemoveReaction("weine", R_ME|R_NOONE);
AddReaction("danke", R_ME,
({ 1, "sage Solange Du immer bezahlst, brauchst Du Dich nicht zu bedanken."}));
AddReaction("grinse", R_ME,
({ 1, "grins &name gerissen" }));
AddReaction("strecke", R_ME,
({ 1, "emote ist empoert", 1, "sage Diese Jugend von Heute!!" }));
AddReaction("liebe", R_OTHER,
({ 2, "denke Wer bezahlt hier wen?" }));
AddReaction("druecke", R_ME,
({ 1, "sage Lass mich in Ruh."}));
AddReaction("nicke", R_ME,
({ 1, "nicke &name wichtigtuerisch"}));
AddReaction("weine", R_ME|R_NOONE,
({ 2, "sage Heul nicht rum, &Name."}));
// Ein paar Chats für bißchen mehr "Leben"
SetChats(3, ({
"Der Haendler beschimpft das Maultier.",
"Das Maultier schaut deprimiert in die Gegend.",
"Der Haendler zerrt an der Leine.",
"Das Maultier bockt und will nicht weitergehen." }));
}
string preise()
{
// MakePriceList wurde geerbt aus std/trade.c und erstellt automagisch
// ein Preisschild mit dem Angebot und der aktuellen Waehrung
PL->More(MakePriceList("Preisliste", "", 2, ({
({"Weintraube", 250}),
({"Tuch", 30}),
({"Fuellung Wasser", 200}),
({"Glasflasche", 450}), 55));
return "\n";
}
int kaufe(string str)
{
int preis;
string mess, was;
mixed *kauf;
object ob;
// Wenn der Spieler grad unser Feind ist, verkaufen wir ihm natürlich nix.
if (IsEnemy(PL))
{
command_me("sage Dir soll ich noch etwas verkaufen, nachdem Du mich "
"feige angegriffen hast? Das soll wohl ein Witz sein?!?!?");
return 1;
}
notify_fail("WAS willst Du kaufen?\n");
// Wir brauchen ein Argument, das uns angibt, was der Spieler kaufen will.
// Ist keins angegeben, geben wir die Fehlermeldung aus, die wir mit notify_fail
// festgelegt haben
if (!str || !stringp(str) || !strlen(str)) return 0;
// Wir wandeln alle Großbuchstaben in dem Argument in Kleinbuchstaben.
// Das erleichtert uns die Arbeit und der Spieler kann auch "kaufe Tuch"
// statt "kaufe tuch" schreiben, ohne, daß es wen stört :-))
str = lower_case(str);
// Nun schaun wir, was der Spieler denn konkret will. Je nach Fall legen wir
// den Preis und das zu clonende Objekt (was) fest. mess ist der Text, den
// der Spieler bei der Uebergabe bekommt.
switch(str)
{
case "weintraube": case "weintrauben": case "wein":
case "traube": case "trauben":
mess = "Der Haendler reicht Dir aus einem seiner Koerbe "
"eine frische Traube Weinbeeren.\n";
was = "/doc/beispiele/weintraube";
preis = 500;
break;
case "wasser":
// Das Wasser hat eine Sonderrolle
tell_object(PL, "Der Haendler sagt: Frag mich doch einfach, "
"ob ich Dir Deine Flasche auffuelle.\n");
return 1;
break;
case "flasche": case "glasflasche": case "flaschen": case "glasflaschen":
mess = "Der Haendler reicht Dir aus einem seiner Koerbe eine "
"leere Glasflasche.\n";
was = "/doc/beispiele/lcontainer/flasche";
preis = 900;
break;
case "tuch":
mess = "Der Haendler reicht Dir aus einem seiner Koerbe ein "
"weiches Tuch.\n";
was = "/doc/beispiele/tuch";
preis = 60;
break;
default:
tell_object(PL, "Sowas kannst Du hier nicht kaufen.\n");
return 1;
}
// Mit QueryMoney schaun wir, was der Spieler an Geld in der von uns
// gewünschten Währung hat. Ist es zu wenig, verkaufen wir natürlich
// nicht.
if (PL->QueryMoney(QueryProp(P_CURRENCY)) < preis)
{
tell_object(PL, break_string(
"Der Haendler schaut Dich geringschaetzig an und meint: "
"Du hast nicht genug Geld bei Dir.\n"));
return 1;
}
// Mit AddMoney kann man das Barvermögen beeinflussen. Wir reduzieren das
// des Spielers um den zu zahlenden Preis.
PL->AddMoney(QueryProp(P_CURRENCY), -preis);
// Für die Statistik:
// Wir teilen der Zentralbank mit, wieviel Geld wir eingenommen haben
ZENTRALBANK->PutMoney(ME, preis);
// Das Clonen der verkauften Güter
ob = clone_object(was);
// Ausgabe der Meldung an den Spieler
tell_object(PL, mess);
// Und die Uebergabe des Objektes an den Spieler
// Hat die Uebergabe nicht geklappt, legen wir den bezahlten Gegenstand im
// Raum ab.
if (ob->move(PL) < MOVE_OK)
{
tell_object(PL, break_string(
"Der Haendler sagt: Du kannst " + ob->name(WEN, NAME_AUTO) +
" nicht mehr tragen. Ich lege " + ob->QueryPronoun(WEN) +
" hier hin."));
return ob->move(environment(ME), M_PUT);
}
// Und nun noch eine Meldung an die Umgebung.
tell_room(environment(ME),
PL->name(WER, NAME_AUTO|NAME_CAP) + " kauft " +
ob->name(WEN, NAME_INDEF) + ".\n", ({PL}) );
return 1;
}
// Dies Funktion wird durch AddInfo aufgerufen. Sie soll uns einen Antwort-String
// zurückgeben über Erfolg oder Mißerfolg des Auffüllens
string auffuellen()
{
int am, preis;
object *flaschen, *leer;
// Der Preis für das Auffüllen des Gefäßes in Grundeinheiten
preis = 200;
// Lcontainer erkennt man an der Aufnahmefähigkeit von Flüssigkeiten
// -> LCNT_MAXCAPA
// Wir suchen alle, auf die das zutrifft aus dem Inventar des Spielers
flaschen = filter_objects(all_inventory(PL), "QueryProp", P_LCNT_MAXCAPA);
if (!sizeof(flaschen))
return "sagt: Du hast kein geeignetes Gefaess bei Dir.";
// IsEmpty ist eine interne Funktion der Lcontainer. Sie gibt 1 zurück, wenn
// der Behälter leer ist.
leer = filter_objects(flaschen, "IsEmpty");
// In Lcontainern können sich Flüssigkeiten vermischen. Das wollen wir
// hier nicht. Schließlich geh ich auch nicht mit ner halben Flasche Bier
// an den Brunnen und füll sie mit Wasser auf ;-))
if (!sizeof(leer))
return "sagt: Du hast keine leeres Gefaess bei Dir.";
// Wieviel paßt rein in das Gefäß? Wir wollen es ganz füllen.
am = leer[0]->QueryProp(P_LCNT_MAXCAPA);
// Hat der Spieler genug Geld?
if (!PL->AddMoney(QueryProp(P_CURRENCY), -preis))
return "Der Haendler schaut Dich geringschaetzig an und meint: "
"Du hast nicht genug Geld bei Dir.\n";
// Auffüllen des Gefäßes und Ausgabe des Antwortstrings
if (leer[0]->AddLiquid(am, "wasser", "Wasser", am/10, 0, 0, am/2))
return "oeffnet einen seiner Wasserschlaeuche und fuellt Dir Deine Flasche mit "
"frischem Wasser.";
return "sagt: Etwas geht nicht.";
}
|