Beispieldateien

Ein mobiler Händler

----------



// 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.";
}