#pragma save_binary
#pragma strict_types

#define STEED_PATH "/std/konie/"
// Standardowy shadow jezdzca
#define STD_STEED_SHADOW STEED_PATH + "steed_sh"
// Modul odpowiedzialny za karmienie
#define FEEDING STEED_PATH + "feeding"
// Shadow osoby prowadzacej wierzchowca
#define LEAD_SHADOW STEED_PATH + "lead_sh"
#define ROOM_I_ALLOW_STEED "room_i_allow_steed"
#define ROOM_I_NO_ALLOW_STEED "room_i_allow_steed"
inherit "/std/creature.c";
inherit "/cmd/std/command_driver.c";
inherit "/std/combat/unarmed.c";
// inherit FEEDING;

#include <composite.h>
#include <macros.h>
#include <ss_types.h>
#include <stdproperties.h>
#include <wa_types.h>
#include <cmdparse.h>
#include <pl.h>

// ------- Kilka uzytecznych makr ------- //

#define FAIL(x)   { notify_fail(x); return 0; }
#define NF(x)     notify_fail(x)
#define TP        this_player()
#define HE(x)     (x)->query_pronoun()
#define TO        this_object()


// Subloc jezdzca dla pokazania, ze jedzie na wierzchowcu.
#define RIDER_SUBLOC "_steed"
// Subloc wierzchowca dla pokazania, ze ktos go dosiada.
#define STEED_SUBLOC "_riders"



// ---------- Zmienne globalne ---------- //

static object *Riders = ({ }),
              Leader;                // Living prowadzacy tego wierzchowca
static int    Max_riders,            // Maksymalna ilosc jezdzcow
              Has_riders,            // Ilosc aktualnych jezdzcow
              Last_moved_time,       // Czas ostatniego ruchu wierzchowca
              Mounted_combat,        // Czy walka konna jest dozwolona?
              No_trans,              // Czy transujemy wierzchowca gdy jezdziec jest
                                     // transowany?
              *Redir_skills = ({ }); // Przekierowanie niektorych umow jezdzca

static string *Valid_dest = ({ }),     // Dozwolony cel ruchu gdy dosiadamy konia
              *Invalid_dest = ({ }),   // Niedozwolony cel ruchu gdy dosiadamy konia
              *Invalid_unmounted_dest = ({ }),// j.w. tylko dla nie dosiadanego konia
              Shadow_file;             // Shadow ladowany gdy dosiadamy


// ------------- Prototypy ------------- //

public int mounted_combat();
public int idle_time();
public varargs string composite_riders(object for_obj, int przyp);
public varargs string short_old(object for_obj, int przyp);




// -- Ustawienie shadowa wierzchowca plus funkcje query -- //

/*
 * Nazwa funkcji: set_steed_shadow
 * Opis:          Ustawia nazwe pliku shadowa ktory ma byc
 *                ladowany gdy living dosiada wierzchowca.
 * Argumenty:     string: sciezka do shadowa
 */
public void
set_steed_shadow(string s)
{
   Shadow_file = s;
}

/*
 * Nazwa funkcji: query_steed_shadow
 * Opis:          Zwraca nazwe pliku shadowa, ktory ma byc
 *                ladowany gdy living dosiada wierzchowca.
 * Zwraca:        string: sciezka do shadowa
 */
public string
query_steed_shadow(string s)
{
   return Shadow_file;
}


// -- Ustawianie jezdzcow + funkcje query -- //

/*
 * Nazwa funkcji: query_has_riders
 * Opis:          Ilu jezdzcow dosiada wierzchowca?
 * Zwraca:        int: ilosc jezdzcow
 */
public nomask int
query_has_riders()
{
   return Has_riders;
}

/*
 * Nazwa funkcji: query_driver
 * Opis:          Kto kieruje wierzchowcem?
 * Zwraca:        object - kierujacy
 */
public nomask object
query_driver()
{
   return (Has_riders ? Riders[0] : 0);
}

/*
 * Nazwa funkcji: query_riders
 * Opis:          Kto dosiada wierzchowca?
 * Zwraca:        object* - tablica zawierajaca object(s) jezdzcow
 */
public nomask object*
query_riders()
{
   return Riders;
}

/*
 * Nazwa funkcji: add_riders
 * Opis:          Dodaje object(s) jezdzca. Dodaje propa LIVE_O_STEED
 *                dla jezdzca, shadow jezdzca i RIDER_SUBLOC.
 *                Zwraca notify_fail w przypadku jakis bledow.
 * Argumenty:     mixed - object(s) jezdzca
 * Zwraca:        (int) 1 jesli udane, 0 jesli wystapily bledy (jesli na
 *                koniu nie ma juz miejsca, nieprawidlowy jezdziec albo shadow).
 */
public nomask int
add_riders(mixed rider_ob)
{
   int i;
   object sh;

   // Jesli na koniu nie ma miejsca nie mozemy dodac jezdzca
   if (Has_riders >= Max_riders)
      return 0;

   if (objectp(rider_ob))
      rider_ob = ({ rider_ob });
   if (!sizeof(rider_ob) || !pointerp(rider_ob))
      return 0;

   // Sprawdzamy, czy zaden z obiektow juz nie dosiada wierzchowca
   i = sizeof(rider_ob);
   while (i--)
      if (rider_ob[i]->query_prop(LIVE_O_STEED))
         return 0;

   // Dodajemy propa i shadowa do jezdzca
   setuid();
   seteuid(getuid());
   i = sizeof(rider_ob);
   while (i--)
   {
      sh = clone_object(Shadow_file);
      // Sprawdzamy, czy shadow jest prawidlowym shadowem jezdzca
      if (!sh->is_steed_shadow())
      {
         sh->remove_object();
         rider_ob->catch_tell("Nieprawidlowy shadow jezdzca!\n");
      }
      sh->shadow_me(rider_ob[i]);
      sh->set_steed(this_object());

      rider_ob[i]->add_prop(LIVE_O_STEED, this_object());
      rider_ob[i]->add_subloc(RIDER_SUBLOC, this_object(), 0);
   }

   Riders += rider_ob;
   Has_riders = sizeof(Riders);

   return 1;
}

/*
 * Nazwa funkcji: remove_rider
 * Opis:          Usuniecie jezdzca. Usuwa propa LIVE_O_STEED z
 *                jezdzca i subloc RIDER_SUBLOC z wierzchowca.
 *                Nie usuwa shadowa jezdzca.
 * Argumenty:     object - obiekt jezdzca
 * Zwraca:        (int) 0 jesli nie bylo takiego jezdzca na wierzchowcu
 */
public nomask int
remove_rider(object rider_ob)
{
   if (member_array(rider_ob, Riders) < 0)
      return 0;

   Riders -= ({ rider_ob, 0 });
   rider_ob->remove_prop(LIVE_O_STEED);
   rider_ob->remove_subloc(RIDER_SUBLOC);
   Has_riders = sizeof(Riders);

   return 1;
}

/*
 * Nazwa funkcji: set_max_riders
 * Opis:          Ustawia maksymalna ilosc jezdzcow dla wierzchowca.
 * Argumenty:     int - max ilosc jezdzcow
 */
public nomask void
set_max_riders(int i)
{
   Max_riders = i;
}

/*
 * Nazwa funkcji: query_max_riders
 * Opis:          Zwraca maxymalna ilosc jezdzcow dla wierzchowca.
 * Zwraca:        int - max ilosc jezdzcow
 */
public nomask int
query_max_riders()
{
   return Max_riders;
}


// -- Hooki zwracane w roznych przypadkach -- //

/*
 * Nazwa funkcji: mount_hook
 * Opis:          Wysyla wiadomosc kiedy living dosiada wierzchowca.
 *                Wywolywany przez do_mount jesli wylaczony silent mode.
 * Argumenty:     object - living, ktory dosiada wierzchowca
 */
public void
mount_hook(object o)
{
   o->catch_msg("Dosiadasz " + QIMIE(this_object(), PL_DOP) + ".\n");
   saybb(QCIMIE(o, PL_MIA) + " dosiada " + QIMIE(this_object(), PL_DOP)
       + ".\n");
}

/*
 * Nazwa funkcji: dismount_hook
 * Opis:          Wysyla wiadomosc kiedy living zsiada z wierzchowca.
 *                Wywolywany przez sh_do_dismount jesli wylaczony silent mode.
 * Argumenty:     object - living, ktory zsiada z wierzchowca
 */
public void
dismount_hook(object o)
{
   o->catch_msg("Zsiadasz z " + QIMIE(this_object(), PL_DOP) + ".\n");
   saybb(QCIMIE(o, PL_MIA) + " zsiada z " + QIMIE(this_object(), PL_DOP)
      + ".\n");
}

/*
 * Nazwa funkcji: is_not_driver_hook
 * Opis:          Wysyla wiadomosc, jesli jeden z jezdzcow chce sie ruszyc,
 *                ale to nie on kieruje wierzchowcem.
 *                Wywolywany przez query_cannot_move_to w tym obiekcie.
 * Argumenty:     object - living, do ktorego ma byc wyslany msg
 */
public void
is_not_driver_hook(object o)
{
   o->catch_msg("To nie ty trzymasz wodze " + QIMIE(this_object(), PL_DOP)

      + " wiec jak chcesz " + this_object()->koncowka("nim", "nia")
      + " kierowac?\n");
}

/*
 * Nazwa funkcji: invalid_dest_hook
 * Opis:          Wysyla wiadomosc jesli wierzchowiec nie moze gdzies isc
 *                poniewaz check_destination zabrania tego.
 *                Wywolywane przez query_cannot_move_to w tym obiekcie.
 * Argumenty:     object - living, do ktorego ma byc wyslany msg
 *                opcionalnie: string where_to, e.g. "na statek",
 *                   "na polnoc".
 */
public varargs void
invalid_dest_hook(object o, string where_to)
{
   o->catch_msg(QCIMIE(this_object(), PL_MIA) +
      " nie moze isc " + (strlen(where_to) ? where_to : "w ta strone") +
      ", moze lepiej najpierw z " + this_object()->koncowka("niego", "niej") +
      " zsiadz?\n");

}

/*
 * Nazwa funkcji: steed_is_tired_hook
 * Opis:          Wysyla wiadomosc gdy wierzchowiec jest zbyt zmeczony by sie ruszac.
 *                Wywolywane przez query_cannot_move_to w tym obiekcie.
 * Argumenty:     object - living, do ktorego ma byc wyslany msg
 */
public void
steed_is_tired_hook(object o)
{
   o->catch_msg(QCIMIE(this_object(), PL_MIA) +
      " jest zbyt zmeczony by sie ruszyc.\n");
}

/*
 * Nazwa funkcji: lead_hook
 * Opis:          Wysyla wiadomosc gdy gracz zaczyna prowadzic wierzchowca.
 * Argumenty:     object living
 */
public void
lead_hook(object o)
{
   o->catch_msg("Zaczynasz prowadzic " + QIMIE(this_object(), PL_BIE)
      + " lapiac wodze tuz przy uzdzie.\n");
   saybb(QCIMIE(o, PL_MIA) + " zaczyna prowadzic " +
      QIMIE(this_object(), PL_BIE) + " lapiac wodze tuz przy uzdzie.\n");
}

/*
 * Nazwa funkcji: unlead_hook
 * Opis:          Wysyla wiadomosc gdy gracz przestaje prowadzic wierzchowca.
 * Argumenty:     object living
 */
public void
unlead_hook(object o)
{
   o->catch_msg("Puszczasz wodze przestajac prowadzic " + QIMIE(this_object(),
PL_BIE)
      + ".\n");
   saybb(QCIMIE(o, PL_MIA) + " puszcza wodze przestajac prowadzic " +
      QIMIE(this_object(), PL_BIE) + ".\n");
}


// -- Dosiadanie i zsiadanie z wierzchowca -- //

/*
 * Nazwa funkcji: can_mount
 * Opis:          Czy living ma wystarczajace umy, zeby dosiasc wierzchowca?
 *                Wywolywane przez do_mount. Mozna zamienic na wlasne kryteria
 *                jesli trzeba. notify_fail nie zdefiniowany.
 * Argumenty:     object - living probujacy dosiasc
 * Zwraca:        int - jesli dosiadanie powiodlo sie zwraca 1
 */
public int
can_mount(object o)
{

   if (o->query_skill(112) <= 25) // :PPP
   {
      o->catch_msg("Nie masz wystarczajacych umiejetnosci, by okielznac " +
         QIMIE(this_object(), PL_BIE) + ".\n");
      return 0;
   }


   if ((environment(o)->query_prop(ROOM_I_INSIDE)) &&
      (!(environment(o)->query_prop(ROOM_I_ALLOW_STEED))))
   {
      o->catch_msg("Jest tutaj zbyt ciasno, bys mogl dosiasc " +
          QIMIE(this_object(), PL_DOP) + ".\n");
      return 0;
   }
   return 1;
}

/*
 * Nazwa funkcji: check_combat
 * Opis:          Czy ten wierzchowiec umozliwia walke konna?
 *                Jesli nie, czy living albo wierzchowiec sa zaangarzowani w walke?
 *                Wywolywane do_mount. notify_fail nie zdefiniowane.
 * Argumenty:     object - living object
 * Zwraca:        int - prawdziwie, jesli walka nie jest przeciwwskazaniem do dosiadania.
 */
public int
check_combat(object o)
{
   if (mounted_combat())
      return 1;

   if (objectp(o->query_attack()))
   {
      o->catch_msg("Jestes zbyt zajety walka, by dosiasc " +
         QIMIE(this_object(), PL_DOP) + ".\n");
      return 0;
   }

   if (objectp(query_attack()))
   {
      o->catch_msg(QCIMIE(this_object(), PL_MIA)  + " jest zaangazowany w walke, " +
         "proba dosiadania " + this_object()->koncowka("go", "jej") +
         " w tym momencie nie bylaby madra.\n");
      return 0;
   }

   return 1;
}

/*
 * Nazwa funkcji: do_mount
 * Opis:          Pozwala livingowi dosiasc wierzchowca, wywoluje can_mount i check_combat
 *                by sprawdzic, czy dosiadanie jest mozliwe..
 * Argumenty:     object - living object
 *                int - jesli prawdziwe: silent mode, nie powiadamia otoczenia
 *                   gdy living dosiada wierzchowca.
 *                               (0 default)
 * Zwraca:        0 - akcja sie nie powiodla, ale moze byc podjeta proba na innym wierzchowcu
 *                1 - syntax byl ok ale niekoniecznie musi dosiasc
 */
public varargs int
do_mount(object o, int silent = 0)
{
object sh;

   if (environment() != environment(o))
      return 0;

   if (objectp(Leader))
      FAIL("Nie mozesz dosiasc " + this_object()->query_imie(o, PL_DOP) +
      " gdy ktos go prowadzi.\n");

   if (Has_riders >= Max_riders)
      FAIL("Na " + this_object()->query_imie(o, PL_MIE)
      + " nie ma miejsca dla kolejnego jezdzca.\n");

   if (o->query_prop(LIVE_O_STEED))
   {
      write("Juz dosiadasz wierzchowca.\n");
      return 1;
   }

   if (member_array(o, Riders) >= 0)
   {
      o->catch_msg("Juz dosiadasz " + QIMIE(this_object(), PL_MIA) + ".\n");
      return 1;
   }

   // Czy living moze dosiasc wierzchowca?
   if (!can_mount(o))
      return 1;

   // Czy living albo wierzchowiec sa zaangarzowani w walke?
   if (!check_combat(o))
      return 1;

   // Proba dodania jezdzca (powinna zawsze sie teraz powiesc)
   if (!add_riders(o))
      return 1;

   if (!silent)
      mount_hook(o);

   // Ujawnij livinga jesli jest ukryty, zawsze powiedz mu, ze jest ujawniany
   o->reveal_me(1);

   return 1;
}

/*
 * Nazwa funkcji: can_dismount
 * Opis:          Czy living moze zsiasc z wierzchowca? Uzyteczny, by zabronic zsiadania
 *                na jakis lokacjach (np. gdy latamy (smok tez wierzchowiec ;P).
 *                Wywolywane przez sh_do_dismount. Mozna zamienic wlasnymi kryteriami jesli
 *                trzeba.
 * Argumenty:     object - living object
 * Zwraca:        int - true jesli sie powiedzie
 */
public int
can_dismount(object o)
{
   return 1;
}

/*
 * Nazwa funkcji: sh_do_dismount
 * Opis:          Pozwala livingowi zsiasc, ale nie usuwa shadowa.
 *                Ta funkcja jest najczesciej forsowana przez shadow (ale nie chcemy go usuwac).
 *                Wywolywane przez do_dismount albo shadow jezdzca.
 *                Wywoluje can_dismount by sprawdzic, czy jezdziec moze zsiasc.
 * Argumenty:     object - living object
 *                int - jesli true: silent mode, nie powiadamiamy otoczenia.
 *                               (default 0)
 *                int - forsuje dismount, ignoruje can_dismount. (default 0)
 * Zwraca:        1 - jesli powodzenie, 0 - niepowodzenie
 */
public varargs int
sh_do_dismount(object o, int silent = 0, int force = 0)
{
   // Czy living jest jezdzcem tego wierzchowca?
   if (member_array(o, Riders) < 0)
      return 0;

   // Czy living moze zsiasc? Jesli forsowane - zawsze moze.
   if (!force && !can_dismount(o))
      return 0;

   remove_rider(o);

   if (!silent)
      dismount_hook(o);

   return 1;
}

/*
 * Nazwa funkcji: do_dismount
 * Opis:          Living zsiada z wierzchowca, usuwamy shadow.
 * Argumenty:     object - living object
 *                int - jesli silent nie powiadamiamy otoczenia (default 0)
 * Zwraca:        0 - nie udalo sie zsiasc, 1 - powodzenie
 */
public varargs int
do_dismount(object rider_ob, int silent = 0, int force = 0)
{
   if (!sh_do_dismount(rider_ob, silent, force))
      return 0;

   rider_ob->remove_steed_shadow();
   return 1;
}

/*
 * Nazwa funkcji: dismount_all
 * Opis:          Wszyscy jezdzcy zsiadaja z wierzchowca.
 * Argumenty:     int silent: 1 ciche zsiadanie (0 default)
 *                int force: 1 forsuje jezdzcow ignorujac can_dismount
 *                 (0 by default).
 */
public varargs void
dismount_all(int silent = 0, int force = 0)
{
   map(Riders, &do_dismount(, silent, force));
}


// -- Funkcje sprawdzajace cel ruchu wierzchowca -- //

/*
 * Nazwa funkcji: query_valid_dest
 * Opis:          Zwraca tablice propow zawsze poprawnych docelowych
 *                lokacji (bez wzgledu niepoprawne propy)
 *                gdy wierzchowiec ma jezdzca.
 * Zwraca:        string *
 */
public string*
query_valid_dest()
{
   return Valid_dest;
}

/*
 * Nazwa funkcji: set_valid_dest
 * Opis:          Ustawia propy zawsze poprawne dla docelowych lokacji
 *                (bez wzgledu na niepoprawne propy)
 *                gdy wierzchowiec ma jezdzca.
 * Arguments:     mixed - pojedynczy prop albo tablica propow
 */
public void
set_valid_dest(mixed t)
{
   if (stringp(t))
      t = ({ t });
   if (pointerp(t))
      Valid_dest = t;
}

// patrz set_valid_dest
public void
add_valid_dest(mixed t)
{
   if (stringp(t))
      t = ({ t });
   if (pointerp(t))
      Valid_dest += t;
}

/*
 * Nazwa funkcji: query_invalid_dest
 * Opis:          Zwraca tablice propow zabraniajacych wejscie
 *                na docelowa lokacje gdy wierzchowiec ma jezdzca.
 * Zwraca:        string *
 */
public string*
query_invalid_dest()
{
   return Invalid_dest;
}

/*
 * Nazwa funkcji: set_invalid_dest
 * Opis:          Ustawia propy zabraniajace wejsciena docelowa
 *                lokacje gdy wierzchowiec ma jezdzca.
 * Argumenty:     mixed - pojedynczy prop albo tablica propow
 */
public void
set_invalid_dest(mixed t)
{
   if (stringp(t))
      t = ({ t });
   if (pointerp(t))
      Invalid_dest = t;
}

// patrz set_invalid_dest
public void
add_invalid_dest(mixed t)
{
   if (stringp(t))
      t = ({ t });
   if (pointerp(t))
      Invalid_dest += t;
}

/*
 * Nazwa funkcji: query_invalid_unmounted_dest
 * Opis:          Zwraca tablice propow zabraniajacych wejscie na
 *                docelowa lokacje gdy wierzchowiec nie ma jezdzca
 * Zwraca:        string *
 */
public string*
query_invalid_unmounted_dest()
{
   return Invalid_unmounted_dest;
}

/*
 * Nazwa funkcji: set_invalid_unmounted_dest
 * Opis:          Ustawia propy zabraniajace wejsciena docelowa
 *                lokacje gdy wierzchowiec nie ma jezdzca.
 * Argumenty:     mixed - pojedynczy prop albo tablica propow
 */
public void
set_invalid_unmounted_dest(mixed t)
{
   if (stringp(t))
      t = ({ t });
   if (pointerp(t))
      Invalid_unmounted_dest = t;
}

// patrz set_invalid_unmounted_dest
public void
add_invalid_unmounted_dest(mixed t)
{
   if (stringp(t))
      t = ({ t });
   if (pointerp(t))
      Invalid_unmounted_dest += t;
}

/*
 * Nazwa funkcji: check_mounted_destination
 * Opis:          Sprawdza, czy lokacja jest poprawna dla wierzchowca.
 *                (e.g. nie wchodzic do domkow itp.)
 *                Uzywana tylko, gdy wierzchowiec ma jezdzca.
 *                Lokacje z propami takimi jak te z query_valid_dest() sa
 *                widziane jako poprawne cele ruchu.
 *                Lokacje z propami takimi jak te z query_invalid_dest() sa
 *                widziane jako niepoprawne cele ruchu. Poprawne propy maja
 *                wiekszy priorytet.
 * Argumenty:     object - obiekt docelowego ruchu
 * Zwraca:        int - true jesli cel ruchu jest poprawny
 */
public int
check_mounted_destination(object to_dest)
{
int i;

   // Sprawdzamy najpierw poprawne cele
   i = sizeof(Valid_dest);
   while (i--)
      if (to_dest->query_prop(Valid_dest[i]))
         return 1;

   // Sprawdzamy niepoprawne cele
   i = sizeof(Invalid_dest);
   while (i--)
      if (to_dest->query_prop(Invalid_dest[i]))
         return 0;

   return 1;
}

// Podobne do check_mounted_destination,
// ale dla przypadku, gdy wierzchowiec nie ma jezdzca.
public int
check_unmounted_destination(object to_dest)
{
int i;

   // Sprawdzamy niepoprawne cele
   i = sizeof(Invalid_unmounted_dest);
   while (i--)
      if (to_dest->query_prop(Invalid_unmounted_dest[i]))
         return 0;

   return 1;
}

/*
 * Nazwa funkcji: check_destination
 * Opis:          Sprawdza docelowa lokacje, do ktorej chce sie ruszyc
 *                wierzchowiec. Najczesciej wywolywana przez shadow jezdzca.
 *                Wywoluje check_mounted_destination albo
 *                check_unmounted_destination w zaleznosci od tego,
 *                czy wierzchowiec ma jezdzcow.
 * Argumenty:     mixed docelowy object/nazwa pliku
 * Zwraca:        int 1 jesli wierzchowiec moze tam isc
 */
public int
check_destination(mixed to_dest)
{
   // Sprawdzamy, czy cel moze sie zaladowac, jesli moze
   // to czy wierzchowiec moze wejsc. Jesli nie przerywamy.
   if (!stringp(LOAD_ERR(to_dest)))
      if (!objectp(to_dest))
         to_dest = find_object(to_dest);

   return (Has_riders ?
      check_mounted_destination(to_dest) :
      check_unmounted_destination(to_dest));
}


// -- Funkcje set & query dla przekierowan umow jezdzca do wierzchowca -- //

/*
 * Nazwa funkcji: query_redir_skills
 * Opis:          Zwraca numery umow jezdzca, ktore sa przekierowywane
 *                przez shadow jezdzca do wierzchowca.
 * Zwraca:        int * tablica numerow umow
 */
public int*
query_redir_skills()
{
   return Redir_skills;
}

/*
 * Nazwa funkcji: set_redir_skills
 * Opis:          Ustawia numery umow jezdzca, ktore sa przekierowywane
 *                przez shadow jezdzca do wierzchowca. (np. wspinaczka).
 * Argumenty:     mixed - numer uma albo tablice numerow umow
 */
public void
set_redir_skills(mixed t)
{
   if (intp(t))
      t = ({ t });
   if (pointerp(t))
      Redir_skills = t;
}


// -- Funkcje zwiazane z walka -- //

// Uzywamy toolsow
public string
query_combat_file()
{
   return "/std/combat/ctool";
}

/*
 * Nazwa funkcji: allow_mounted_combat
 * Opis:          Udostepnia albo zabrania walki z wierzchowca w tym obiekcie.
 * Argumenty:     int 0 - false, 1 - true
 */
public void
allow_mounted_combat(int t)
{
   Mounted_combat = t;
}

/*
 * Nazwa funkcji: mounted_combat
 * Opis:          Czy walka konna jest dostepna w tym obiekcie wierzchowca?
 * Zwraca:        int 0 - false, 1 - true
 */
public int
mounted_combat()
{
   return Mounted_combat;
}

// Sprawdza mounted_combat() - jesli walka z wierzchowca niedostepna,
// gdy wierzchowiec zaatakowany - zmuszamy jezdzcow do zejscia z niego
public void
attacked_by(object o)
{
   if (!mounted_combat())  // zmus do zejscia z wierzchowca gdy walka konna niedostepna
      dismount_all();
   else if (member_array(o, Riders) >= 0) // zmus do zejscia, gdy jezdziec mnie zaatakuje
      do_dismount(o);

   ::attacked_by(o);
}

// zmus wszystkich jezdzcow do zejscia gdy wierzchowiec umrze
public void
do_die(object killer)
{
   if (query_hp() > 0)
      return;

   dismount_all(0, 1);
   ::do_die(killer);
}


// -- Funkcje ruchu -- //

// wysyla wiadomosc, wywolywane przez query_cannot_move_to ponizej
public void
give_msg(function msg_function, string where_to)
{
   if (where_to == "M")
      return;
   msg_function();
}

/*
 * Nazwa funkcji: query_cannot_move_to
 * Opis:          Sprawdza, czy wierzchowiec nie moze sie ruszac.
 *                Wywolywane przez move_living w shadowie jezdzca.
 * Argumenty:     object jezdziec, ktory chce sie ruszyc
 *                mixed cel, do ktorego jezdziec chce sie ruszyc
 *                opcjonalnie:
 *                string where_to: np. "wejsc w portal", "isc na polnoc",
 *                   "wejsc na statek".
 * Zwraca:        int 0 jesli mozna isc
 *                    8 nieprawidlowy cel ruchu
 *                    9 living nie kieruje wierzchowcem
 *                   10 wierzchowiec jest zbyt zmeczony
 */
public varargs int
query_cannot_move_to(object living, mixed destination, string where_to)
{
   // Jesli ten jezdziec nie kieruje wierzchowcem nie wykonuj ruchu
   if (Riders[0] != living)
   {
      give_msg(&is_not_driver_hook(living), where_to);
      return 9;
   }

   // Sprawdz, czy wierzchowiec jest zmeczony
   if (!query_fatigue())
   {
      give_msg(&steed_is_tired_hook(living), where_to);
      return 10;
   }

   // Sprawdz, czy wierzchowiec moze isc do docelowej lokacji
   if (!check_destination(destination))
   {
      give_msg(&invalid_dest_hook(living, strlen(where_to) ?
         where_to : "isc w ta strone"), where_to);
      return 8;
   }

   return 0;
}

/*
 * Nazwa funkcji: move_living
 * Opis:          Nagrywa czas kiedy wierzchowiec ostatnio sie ruszyl.
 *                Dalej: jesli wierzchowiec sam sie ruszy (np. spanikuje)
 *                tak samo rusza jezdzcow. Takze sprawdza cel ruchu
 *                jesli wierzchowiec ma jezdzcow.
 * Argumenty:     patrz orginalna funkcja move_living.
 * Zwraca:        patrz orginalna funkcja move_living.
 *                int 8 jesli cel ruchu byl nieprawidlowy
 */
public varargs int
move_living(string how, mixed to_dest, int dont_follow, int no_glance)
{
int    r;
string steed_how;

   // Jesli wierzchowiec ma jezdzcow nie pokazuj ruchu
   steed_how = Has_riders ? "M" : how;

   // Check the destination
   if (!check_destination(to_dest))
      return 8;

   r = ::move_living(steed_how, to_dest, dont_follow, no_glance);

   if (!r)
      Last_moved_time = time();

   // Wierzchowiec ruszyl sie gdzies samemu (np. spanikowal),
   // albo zostal gdzies skierowany przez shadow prowadzenia.
   // Zmusza wszystkich jezdzcow do podazania za nim przez wywolanie starej
   // funkcji move_living.
   Riders->move_living_old(how, to_dest, 1, 0);

   return r;
}

/*
 * Nazwa funkcji: drive_steed
 * Opis:          Pozwala kierujacemu wierzchowcem prowadzic go, zmusza
 *                reszte jezdzcow do podazania razem z wierzchowcem. Rozni sie
 *                od move_living, gdyz pomija pokazywanie jak ruszyli sie jezdzcy.
 *                Poza tym nie sprawdza czy cel ruchu jest prawidlowy.
 *                Nagrywa czas ostatniego ruchu wierzchowca.
 * Argumenty:     patrz orginalna funkcja move_living.
 * Zwraca:        int 8 jesli cel ruchu byl nieprawidlowy
 */
public varargs int
drive_steed(string how, mixed to_dest, int dont_follow, int no_glance)
{
int r;

   r = ::move_living("M", to_dest, dont_follow, no_glance);

   if (!r)
      Last_moved_time = time();

   // Zmusza wspoljezdzcow do ruchu, wywoluje orginalna funkcje move_living
   // w jezdzcach.
   Riders[1..]->move_living_old(how, to_dest, 1, 0);
   return r;
}

// Udostepniamy orginalna funkcje move_living
public varargs int
move_living_old(string how, mixed to_dest, int dont_follow, int no_glance)
{
   return ::move_living(how, to_dest, dont_follow, no_glance);
}

/*
 * Nazwa funkcji: set_no_trans
 * Opis:          Czy transujemy wierzchowca gdy jezdziec jest transowany?
 *                (Z "X" jako pierwszy argument w move_living).
 * Argumenty:     int 1 zmusza jezdzca do zejscia z wierzchowca gdy go transujemy
 *                    0 transportuje wierzchowca z jezdzcem jesli nie ma wiecej jezdzcow
 */
public void
set_no_trans(int i)
{
   No_trans = (i ? 1 : 0);
}

/*
 * Nazwa funkcji: query_no_trans
 * Opis:          Czy transujemy wierzchowca gdy jezdziec jest transowany?
 *                (Z "X" jako pierwszy argument w move_living).
 * Zwraca:        int 1 zmusza jezdzca do zejscia z wierzchowca gdy go transujemy
 *                    0 transportuje wierzchowca z jezdzcem jesli nie ma wiecej jezdzcow

public int
query_no_trans()
{
   return No_trans;
}


// -- Creation stuff -- //

/*
 * Nazwa funkcji: create_steed
 * Opis:          Funkcja tworzaca wierzchowca (definiowana w pliku
wierzchowca)
 */
public void
create_steed()
{
   ustaw_odmiane_rasy(({"kon","konia","koniowi","konia","koniem","koniu"}),
                   ({"konie","koni","koniom","konie","konmi","koniach"}),
		       PL_MESKI_OS);
   set_gender(G_MALE);
}

/*
 * Nazwa funkcji: configure_steed
 * Opis:          Dodaje wierzchowcowi kilka standardowych hitlocow i attackow,
 *                wywolywana z create_creature. Przedefiniuj, jesli chcesz miec
 *                inne hitloc albo attacks.
 */
public void
configure_steed()
{
   set_attack_unarmed(0, 70, 20, W_IMPALE | W_SLASH, 10, "zebami");
   set_attack_unarmed(1, 60, 40, W_BLUDGEON, 30, "prawym kopytem");
   set_attack_unarmed(2, 60, 40, W_BLUDGEON, 30, "lewym kopytem");
   set_attack_unarmed(3, 70, 60, W_BLUDGEON, 30, "tylnymi kopytami");

   set_hitloc_unarmed(0, 35, 15, "glowe");
   set_hitloc_unarmed(1, 50, 40, "korpus");
   set_hitloc_unarmed(2, 60, 20, "przednie nogi");
   set_hitloc_unarmed(3, 60, 20, "tylne nogi");
   set_hitloc_unarmed(4, 20, 5, "ogon");
}

nomask void
create_creature()
{
    // Kilka standardowych propow wierzchowca

    add_prop(NPC_I_NO_LOOKS, 1);
    add_prop(NPC_I_NO_RUN_AWAY, 1);
    add_prop(LIVE_I_NEVERKNOWN, 1);
    add_prop(CONT_I_HEIGHT, 200);

    // Dodajemy hitlocs i attacks
    configure_steed();

    // Dodajemy kilka standardowych wartosci
    set_valid_dest(({ ROOM_I_ALLOW_STEED }));
    set_invalid_dest(({ ROOM_I_NO_ALLOW_STEED, ROOM_I_INSIDE }));
    set_invalid_unmounted_dest(({ ROOM_I_NO_ALLOW_STEED }));
    set_redir_skills(({ SS_CLIMB, SS_SWIM, SS_SNEAK, SS_HIDE }));
    Last_moved_time = time();

    // Dodajemy subloc by pokazac, ze jest obecny jezdziec
    add_subloc(STEED_SUBLOC, this_object(), 0);
    set_stats(({5,5,450,1,1,1}));
    set_skill(24,1000);
 

    set_steed_shadow(STD_STEED_SHADOW); // standardowy shadow wierzchowca
    set_max_riders(1);        // maxymalnie jeden jezdziec
    allow_mounted_combat(0);  // zabraniamy walki z wierzchowca
    set_no_trans(1);          // wymuszamy zejscie z wierzchowca gdy jezdziec jest transowany

    create_steed();
}

/*
 * Nazwa funkcji: is_steed
 * Opis:          Czy ten obiekt jest wierzchowcem?
 * Zwraca:        int 1
 */
public nomask int
is_steed()
{
   return 1;
}


// -- Funkcje opisujace  -- //

// Pokazuje nastepujace sublocki::
//    RIDER_SUBLOC: Dodatkowy opis obiektu jezdzca
//    STEED_SUBLOC: Dodatkowy opis obiektu wierzchowca
public string
show_subloc(string subloc, object on, object for_obj)
{
   string objective, verb;

   if (subloc == RIDER_SUBLOC)  // Dodatkowy opis dla jezdzca
   {
      return (on == for_obj ?
         "Siedzisz na " + this_object()->query_imie(for_obj, PL_MIE) + ".\n" :
         "Siedzi wygodnie na "
            + this_object()->query_imie(for_obj, PL_MIE) + ".\n");
   }
   else if (subloc == STEED_SUBLOC)  // Dodatkowy opis dla wierzchowca
   {
      if (!Has_riders)
         return "";

      objective = (on == for_obj ? "ciebie" : this_object()->koncowka("y", "a"));

      return "Jest dosiadan" + objective + " przez " + composite_riders(for_obj, PL_BIE)
         + ".\n";
   }

   return "";
}

// Funkcja zwracajaca imie jezdzca
public string
rider_name(object o, object for_obj, int przyp)
{
    string ty;
    switch(przyp)
    {
        case PL_MIA: {ty = "ty"; break;}
        case PL_DOP: {ty = "ciebie"; break;}
        case PL_CEL: {ty = "tobie"; break;}
        case PL_BIE: {ty = "ciebie"; break;}
        case PL_NAR: {ty = "toba"; break;}
        case PL_MIE: {ty = "tobie"; break;}
    }
   return (for_obj == o ? ty : o->query_imie(for_obj, przyp));
}

// Funkcja opisujaca jezdzcow
public string
composite_riders(object for_obj, int przyp)
{
   return Has_riders ?
      COMPOSITE_WORDS(map(Riders, &rider_name(, for_obj, przyp))) :
      "nikt nie";
}

// Udostepniamy stara funkcje short
public varargs string
short_old(object for_obj, int przyp)
{
   return ::short(for_obj, przyp);
}

// dodajemy jezdzcow do krotkiego opisu
public varargs string
short(object for_obj, int przyp)
{
   string dosiadany;

   // Jesli nie ma jezdzcow, zwracamy orginalny short
   if (!Has_riders)
      return short_old(for_obj, przyp);

   if (!objectp(for_obj))
      for_obj = this_player();

   switch(przyp)
   {
      case PL_MIA: {dosiadany = "dosiadan" + this_object()->koncowka("y", "a");
break;}
      case PL_DOP: {dosiadany = "dosiadane" + this_object()->koncowka("go",
"j"); break;}
      case PL_CEL: {dosiadany = "dosiadane" + this_object()->koncowka("mu",
"j");; break;}
      case PL_BIE: {dosiadany = "dosiadan" + this_object()->koncowka("ego",
"a");; break;}
      case PL_NAR: {dosiadany = "dosiadan" + this_object()->koncowka("ym",
"a");; break;}
      case PL_MIE: {dosiadany = "dosiadan" + this_object()->koncowka("ym",
"ej");; break;}
   }

   return short_old(for_obj, przyp) + " " + dosiadany + " przez "
      + composite_riders(for_obj, PL_BIE);
}


// -- wiadomosci o przybyciu i opuszczeniu lokacji -- //

/*
 * Nazwa funkcji: query_rider_m_in
 * Opis:          Wyswietla wiadomosc o przybyciu jezdzca na tym wierzchowcu.
 *                Wywolywane przez set_steed w shadowie jezdzca.
 * Argumenty:     object jezdziec
 * Zwraca:        string
 */
public string
query_rider_m_in(object rider)
{
   return "przybywa jadac na " + short_old(this_player(), PL_MIE) + ".";
}

/*
 * Nazwa funkcji: query_rider_m_out
 * Opis:          Wyswietla wiadomosc o opuszczeniu lokacji przez  jezdzca.
 *                Wywolywane przez set_steed w shadowie jezdzca.
 * Argumenty:     object rider
 * Zwraca:        string
 */
public string
query_rider_m_out(object rider)
{
   return "jedzie na " + short_old(this_player(), PL_MIE);
}


// -- funkcje prowadzenia za uzde -- //

/*
 * Nazwa funkcji: query_leader
 * Opis:          Kto prowadzi wierzchowca?
 * Zwraca:        object
 */
public object
query_leader()
{
   return Leader;
}

/*
 * Nazwa funkcji: can_lead
 * Opis:          Sprawdzamy, czy living moze prowadzic wierzchowca.
 *                notify_fail nie zdefiniowane.
 * Argumenty:     object living
 * Zwraca:        int 1 jesli living moze prowadzic tego wierzchowca
 */
public int
can_lead(object living)
{
   return 1;
}

/*
 * Nazwa funkcji: do_lead
 * Opis:          Living zaczyna prowadzic wierzchowca za uzde.
 * Argumenty:     object: nasz przyszly prowadzacy
 * Zwraca:        int powodzenie
 */
public int
do_lead(object o)
{
   object shadow;

   if (!can_lead(o))
      return 1;

   Leader = o;
   // Sprawdzamy, czy living prowadzi innego wierzchowca
   if (!Leader->query_leading_steed())
   {
      shadow = clone_object(LEAD_SHADOW);
      shadow->shadow_me(Leader);
   }

   Leader->add_steed_follow(this_object());

   // Dajemy wiadomosc, ze living zaczyna prowadzic wierzchowca
   lead_hook(Leader);
   return 1;
}

/*
 * Nazwa funkcji: do_unlead
 * Opis:          Living przestaje prowadzic wierzchowca za uzde.
 * Argumenty:     object przypuszczalny prowadzacy
 *                int - opcionalnie: powiadamia shadow prowadzacego, ze
 *                   juz nie prowadzi wierzchowca.
 * Zwraca:        int powodzenie
 */
public varargs int
do_unlead(object o, int notify_shadow = 0)
{
   if (Leader != o)
      return 0;
   if (notify_shadow)
      Leader->remove_steed_follow(this_object());

   // Dajemy wiadomosc, ze living przestaje prowadzic wierzchowca
   unlead_hook(Leader);
   Leader = 0;
   return 1;
}


// -- Funkcjie akcji -- //

/*
 * Nazwa funkcji: dismount
 * Opis:          probujemy zsiasc, jesli syntax jest OK wywolujemy
 *                do_dismount w obiekcie wierzchowca.
 * Argumenty:     string - z czego zsiasc?
 * Zwraca:        true jesli powodzenie
 */
public nomask int
dismount(string s)
{
   mixed *o_list;
   int steed, i;

   if (!this_player()->query_prop(LIVE_O_STEED))
      FAIL("Przeciez niczego nie dosiadasz.\n");

   if (!s || !parse_command(s, all_inventory(environment(this_player())),
      "'z' %l:" + PL_DOP, o_list)) 
      
      //|| !sizeof(NORMAL_ACCESS(o_list, visible)))
      FAIL("Z czego chcesz zsiasc?\n");

   steed = o_list[0];

   if (steed == 0)   // zabraniamy "zsiadz z wszystkich koni" albo "zsiadz z koni"
      return 0;
   if (steed > 0)    // udostepniamy "zsiadz z konia"
   {
      if (steed > 1) // zabraniamy "zsiadz z dwoch koni"
         return 0;

      // Probujemy zsiasc z pierwszego, potem drugiego wierzchowca etc.
      o_list = filter(o_list[1..], &->is_steed());
      for (i = 0; i < sizeof(o_list); i++)
         if (o_list[i]->do_dismount(this_player()))
            return 1;
      return 0;
   }
   else              // udostepniamy "zsiadz z drugiego konia"
   {
      if (!o_list[-steed]->is_steed())
         return 0;
      return o_list[-steed]->do_dismount(this_player());
   }

}

/*
 * Nazwa funkcji: lead
 * Opis:          Zaczynamy prowadzic wierzchowca.
 * Argumenty:     string - wierzchowiec, ktorego mamy prowadzic
 * Zwraca:       int 1 jesli powodzenie
 */
public int
lead(string s)
{
   object *o_list;
   object steed;

    o_list = parse_this(s,"%l:"+PL_BIE);

    if (!sizeof(o_list))
	{
	write("Prowadz kogo?\n");
	return 1;
	}

//   if (!s || !parse_command(s, all_inventory(environment(this_player())),
//      "%l:" + PL_BIE, o_list))
//      return 0;
      
   steed = o_list[0];

   // sprawdzamy, czy obiekt jest wierzchowcem
   if (!steed->is_steed())
       {
       write("To nie jest kon.\n");
       return 1;
      }

   // sprawdzamy, czy wierzchowiec jest juz prowadzony przez kogos
   if (objectp(steed->query_leader()))
	{
	write("Kon jest juz przez kogos prowadzony.\n");
	return 1;
	}

   // Wykomentowane - w razie czego odkomentowac
   // Nie pozwalamy prowadzic wierzchowca, gdy juz jakiegos dosiadamy
   //   if (objectp(this_player()->query_prop(LIVE_O_STEED)))
   //      FAIL("Nie mozesz prowadzic " + steed->query_imie(this_player(),PL_DOP) +
   //      " gdy dosiadasz jakiegos wierzchowca.\n");

   // Zabraniamy prowadzic wierzchowcow, na ktorych sa jezdzcy
   if (steed->query_has_riders())
       {
      TP->catch_msg("Nie mozesz prowadzic " + steed->query_imie(this_player(), PL_DOP) +
      " gdy ktos " + steed->koncowka("go", "jej") + " dosiada.\n");
	return 1;
	}

   return steed->do_lead(this_player());
}

/*
 * Function name: mount
 * Opis:          Probujemy dosiasc wierzchowca, sprawdzamy syntax i
 *                czy obiekt jest wierzchowcem (uzywajac is_steed())
 *                a pozniej wywolujemy do_mount w obiekcie wierzchowca
 * Argumenty:     string - opis obiektu
 * Zwraca:        1 - jesli powodzenie
 */
public nomask int
mount(string s)
{
   mixed  *o_list;
   int    i, index;

   if (CAN_SEE_IN_ROOM(this_player()) <= 0)
      FAIL("Jest zbyt ciemno bys mogl czegos dosiasc.\n");

   if (this_player()->query_prop(LIVE_O_STEED))
      FAIL("Juz dosiadasz wierzchowca.\n");

   if (!s || !parse_command(s, all_inventory(environment(this_player())),
      "%l:" + PL_DOP, o_list))
      
      // || !sizeof(NORMAL_ACCESS(o_list, visible)))
      FAIL("Czego chcesz dosiasc?\n");

   index = o_list[0];

   if (index == 0)   // zabraniamy "dosiadz wszystkich koni" albo "dosiadz koni"
      FAIL("Chcesz dosiasc wiecej niz jednego wierzchowca na raz?\n");
   if (index > 0)    // udostepniamy "dosiadz konia"
   {
      if (index > 1) // zabraniamy "dosiadz dwoch koni"
         FAIL("Chcesz dosiasc wiecej niz jednego wierzchowca na raz?\n");

      // Probujemy dosiasc pierwszego, potem drugiego wierzchowca etc.
      o_list = filter(o_list[1..], &->is_steed());
      for (i = 0; i < sizeof(o_list); i++)
         if (o_list[i]->do_mount(this_player()))
            return 1;
      return 0;
   }
   else              // udostepniamy "dosiadz drugiego konia"
   {
      if (!o_list[-index]->is_steed())
         FAIL("To nie jest wierzchowiec, ktorego moglbys dosiasc!\n");
      return o_list[-index]->do_mount(this_player());
   }
}

/*
 * Nazwa funkcji: unlead
 * Opis:          Przestajemy prowadzic wierzchowca.
 * Argumenty:     string: opis obiektu, ktorego living chce przestac prowadzic.
 * Zwraca:        int powodzenie
 */
public int
unlead(string s)
{
   object *o_list;
   object steed;

   if (!s || !parse_command(s, all_inventory(environment(this_player())),
      "'prowadzic' %l:" + PL_BIE, o_list))
      return 0;
   if (sizeof(o_list) > 2)
      return 0;
   steed = o_list[1];
   // sprawdzamy, czy to jest wierzchowiec
   if (!steed->is_steed())
      return 0;

   return steed->do_unlead(this_player(), 1);
}

void
init_living()
{
   ::init_living();
   add_action(dismount, "zsiadz");
// add_action(feed, "nakarm");
   add_action(lead, "prowadz");
   add_action(unlead, "przestan");
   add_action(mount, "dosiadz");
}


// -- Reszta -- //

// Kiedy wierzchowiec jest destructowany, wszyscy powinni najpierw
// zsiasc z niego, a prowadzacy przestac go prowadzic.
public void
remove_object()
{
   dismount_all(0, 1);
   if (objectp(Leader))
      do_unlead(Leader, 1);
   ::remove_object();
}

/*
 * Nazwa funkcji: idle_time
 * Opis:          Jak dlugo wierzchowiec nie byl ruszany?
 * Zwraca:        int - czas w sekundach
 */
public int
idle_time()
{
   return time() - Last_moved_time;
}
