/*
 *  Yet another dinosaur by foslay
 *  You can ride on this one.
 */

#include <escoryn.h> // added Escoryn defines, Chameloid, 21-Nov-98

#include "/players/foslay/inc.h"

#define DINO "/players/foslay/obj/dino"
#define DINOPIC ES_PICDIR
#define DINO_ROOM "/players/foslay/room/dino"

#define HEAD 0
#define BACK 1
#define TAIL 2
#define BACK2HEAD 3
#define TAIL2BACK 4
#define TAIL_BUSY 5

#include <wizlevels.h>
#include <prop/ladder.h>

inherit "/obj/monster";
inherit "/basic/orientation";

mixed *dino = ({ 0,0,0,0,0,0 }); /* shared between all 3 dino parts */
int part = HEAD;

string dino_pic;

query_dino() { return dino; }

reset (arg)
{
  ::reset (arg);

  if (!clonep()) {
    if (!dino[HEAD]) {
      clone_object(DINO);
    }
    return;
  }
  if (arg) return;

  set_name ("dino");
  set_race ("dinosaur");
  set_level (20);

  set_property ( P_LADDER_EXIT, ({ DINO_ROOM, 0, ({ "dino", "dinosaur" }), DINO_ROOM }) );

  dino = DINO -> query_dino();

  if (!dino[HEAD])
    create_dino ();
}

init()
{
  if (part != TAIL)
    return;

  add_action ("climb_dino","climb");
}

extra_long () { return dino_pic; }

climb_dino (str)
{
  if (!id(str)) return 0;

  if (this_player () -> query_level () < WL_WIZARD)
  {
    notify_fail ("Sorry, only wizards can climb on ths dinosaur.\n");
    return 0;
  }
  this_player()->move_player("up",DINO_ROOM);
  return 1;
}

#if 1
gimme_exit (object room, int flag)
{
  mixed *exits;
  int i;

  if ((exits = room -> query_exit ()) == 0)
    exits = ({ ({ "down" }), ({ "/dev/null" }) });
  i = random (sizeof (exits[0]));
  if (flag)
    write ("Exit to the " + exits[0][i] + " leads to " + exits[1][i] + "\n");
  return ({ exits[0][i], exits[1][i] });
}
#endif

reset_dino ()
{
  move_dino ("up", ES_ROADDIR"bushes");
  move_dino ();
  move_dino ();
}

notify_destruct () /* can't leave a half dino lying around */
{
  object d;
  int t;

  tell_room (environment (), "The dinosaur disappears in a puff of smoke.\n");

  if (dino[HEAD] || dino[BACK] || dino[TAIL])
  {
    dino[part] = 0;
    for (t=0; t<3; t++)
      if (dino[t])
        destruct (dino[t]);

    if (d = find_object ( DINO ))
      destruct (d);
  }
}

create_dino ()
{
#if 0
  call_out ("move_dino_callout", random (20) + 20);
#endif

  dino[HEAD] = this_object ();
  dino[BACK] = clone_object (DINO);
  dino[TAIL] = clone_object (DINO);

  configure_dino (HEAD);
  dino[BACK] -> configure_dino (BACK);
  dino[TAIL] -> configure_dino (TAIL);

  reset_dino ();
}

configure_dino (p) { part = p; if (p == BACK) dino_pic = read_file (DINOPIC); }

exit_of (object room, string dir)
{
  mixed *exits, dest;
  int i;

  if ((exits = room -> query_dest_dir ()) != 0)
  {
    i = random (sizeof (exits) / 2) * 2;
    dest = exits[i];
    dir = exits[i+1];
  }
  else if ((exits = room -> query_exit ()) != 0)
  {
    i = random (sizeof (exits[0]));
    dir = exits[0][i];
    dest = exits[1][i];
  }
  else
  {
    dir = "down";
    dest = "/dev/null";
  }
  return objectp (dest) ? file_name (dest) : dest;
}

move_dino_callout ()
{
  move_dino ();
  call_out ("move_dino_callout", random (20) + 20);
}

dino_goto (string dir, int flag)
{
  mixed *exits;
  int t;

  if ((exits = environment (this_object ()) -> query_exit ()) == 0)
  {
    if (flag)
      write ("Function not supported.\n");
    return 0;
  }
  for (t = 0; t < sizeof (exits[0]); t++)
  {
    if (exits[0][t] == dir)
    {
      if (flag)
	write ("Sending dino to " + exits[1][t] + ".\n");
      move_dino (dir, exits[1][t]);
      return 1;
    }
    else if (flag)
      write ("Direction " + exits[0][t] + " != " + dir + ".\n");
  }
  if (flag)
    write ("No such direction.\n");
  return 0;
}

move_dino (dir, dest)
{
  int mode;

  dest = stringp (dest) ? load_object(dest) : dest;

  if (!dir) {
    dest = exit_of (environment (dino[HEAD]), &dir );
  }
  if (environment(dino[BACK]) == dest)
    move_tight_curve(dir, dest);
  else if (environment(dino[TAIL]) == dest)
    move_curve(dir, dest);
  else
    move_normal(dir, dest);
}

move_tight_curve (string dir, mixed dest)
{
  tell_room (environment (dino[TAIL]),
	"The tail of the dinosaur disappears to the " + dino[TAIL2BACK] + ".\n");

  dino[TAIL] -> move_player(0, environment(dino[BACK]));

  tell_room (environment (dino[BACK]),
	"The dinosaur turns around and looks at its tail.\n");

  dino[TAIL2BACK] = dino[BACK2HEAD];
  dino[TAIL] -> set_dino_desc(2);

  dino[BACK] -> move_player(0, environment(dino[HEAD]));

  tell_room (environment (dino[HEAD]), "The dinosaur turns around.\n");

  dino[BACK2HEAD] = dir;
  dino[BACK] -> set_dino_desc(2);

  dino[HEAD] -> move_player(0, dest);

  dino[HEAD] -> set_dino_desc(2);
}

move_curve (string dir, mixed dest)
{
  tell_room (environment (dino[TAIL]),
	"The head of the dinosaur disappears from the "
	+ orientation_reverse (dir) + " just in time to see\nits tail vanish to the"
	+ dino[TAIL2BACK] + ".\n");

  dino[TAIL] -> move_player(0, environment(dino[BACK]));

  tell_room (environment (dino[BACK]), "The dinosaur leaves "
	+ dino[BACK2HEAD] + ", dragging its huge tail behind it.\n");

  dino[TAIL2BACK] = dino[BACK2HEAD];
  dino[TAIL] -> set_dino_desc(1);

  dino[BACK] -> move_player(0, environment(dino[HEAD]));

  tell_room (environment (dino[HEAD]), "The dinosaur turns " + dir + ".\n");

  dino[BACK2HEAD] = dir;
  dino[BACK] -> set_dino_desc(1);

  dino[HEAD] -> move_player(0, dest);

  dino[HEAD] -> set_dino_desc(1);
}

move_normal (string dir, mixed dest)
{
  if (environment (dino[TAIL])) {
    tell_room (environment (dino[TAIL]),
	"The tail of the dinosaur disappears to the " + dino[TAIL2BACK] + ".\n");
  }

  if (environment (dino[BACK]) ) {
    dino[TAIL] -> move_player(0, environment(dino[BACK]));

    tell_room (environment (dino[BACK]), "The dinosaur leaves "
	+ dino[BACK2HEAD] + ", dragging its huge tail behind it.\n");

    dino[TAIL2BACK] = dino[BACK2HEAD];
    dino[TAIL] -> set_dino_desc(0);
  }

  if (environment (dino[HEAD]) ) {
    dino[BACK] -> move_player(0, environment(dino[HEAD]));

    tell_room (environment (dino[HEAD]), "The dinosaur turns " + dir + ".\n");

    dino[BACK2HEAD] = dir;
    dino[BACK] -> set_dino_desc(0);
  }

  dino[HEAD] -> move_player(0, dest);

  tell_room (environment (dino[HEAD]), "A dinosaur arrives from the "
	+ orientation_reverse (dir) + ".\n");

  dino[HEAD] -> set_dino_desc(0);
}

set_dino_desc (int mode)
{
  switch (part) {
  case HEAD:
    set_alias ("head");
    set_alt_name ("body");
    set_short("A huge dinosaur");
    set_long("\
The huge dinosaur eyes you suspiciously. The giant head looms above you and its\n\
enormous body disappears in the mist to the " +
orientation_reverse (dino[BACK2HEAD]) + ".\n"
    );
    break;

  case BACK:
    set_alias ("legs");
    set_alt_name ("back");
#if 1
    set_short("Back of a huge dinosaur");
#else
    set_short(dino_pic); /* extra_long() now */
#endif
    set_long("\
The huge hind legs of the dinosaur are mud-caked and have left deep footprints\n\
which slowly fill with mud. To the " + dino[BACK2HEAD] + " you see the giant head\n\
of the dinosaur, its tail lies to the " + orientation_reverse(dino[TAIL2BACK])
 + ".\n");
    break;

  case TAIL:
    set_alias ("tail");
    set_alt_name ("rocks");
    if (mode == 2) {
      set_short("The tail of the dinosaur");
      set_long("\
What looks like a chain of pointy rocks at first sight turns out to be the tail\n\
of the huge dinosaur.\n"
      );
    }
    else {
      set_short("The tail of the dinosaur to the " + dino[TAIL2BACK]);
      set_long("\
What looks like a chain of pointy rocks at first sight turns out to be the tail\n\
of the huge dinosaur to the " + dino[TAIL2BACK] + ".\n"
      );
    }
    break;
  }
}

private object victim;

attack () {}

hit_player (int hp)
{
  if (!dino[TAIL_BUSY]) {
    dino[TAIL_BUSY] = 1;
    victim = previous_object ();
    call_out ("dino_strikes_back", 2, 1);
  }
  return 1;
}

dino_strikes_back (action)
{
  if (environment (this_player ()) != environment (this_object ())
      && environment (this_player ()) != environment (dino[HEAD])
      && environment (this_player ()) != environment (dino[BACK])
      && environment (this_player ()) != environment (dino[TAIL]))
  {
    dino[TAIL_BUSY] = 0;
    return;
  }

  switch (action) {
  case 1:
    call_out ("dino_strikes_back", 4, ++action);
    write ("The dinosaur glances sharply at you.\n");
    say ("The dinosaur glances sharply at "
	 + this_player () -> query_name () + ".\n", this_player ());
    break;
  case 2:
    call_out ("dino_strikes_back", 4, ++action);
    write ("The dinosaur slowly turns its huge head towards you.\n");
    say ("The dinosaur slowly turns its huge head towards "
	 + this_player () -> query_name () + ".\n", this_player ());
    break;
  case 3:
    call_out ("dino_strikes_back", 4, ++action);
    write ("The dinosaur growls.\n");
    say ("The dinosaur growls.\n", this_player ());
    break;
  case 4:
    call_out ("flying_lesson", 4, 0);
    call_out ("flying_lesson", 8, 1);
    call_out ("player_falls_down", 12);

    write ("The dinosaur deals a mighty blow with its tail.\n");
    say ("The dinosaur deals a blow with its tail to "
	 + this_player () -> query_name () + " and hurls "
         + this_player () -> query_objective () + " up into the air.\n",
	 this_player ());
    this_player () -> move_living (0, "/players/foslay/room/sky");
    write ("You are airborne.\n");
    tell_room (environment (this_player ()),
	       this_player () -> query_name () + " flies past.\n",
	       ({ this_player () }));
    break;
  }
}

player_falls_down ()
{
  string name;

  dino[TAIL_BUSY] = 0;

  name = this_player () -> query_name ();

  log_file ("foslay.dino", (name ? name : file_name (victim))
			   + " had a flying lesson.\n");

  tell_room (environment (this_player ()),
             this_player () -> query_name ()
	     + " drops like a stone.\n", ({ this_player () }) );

  this_player () -> move_living (0, "/room/church");

  say ("SPLUT! " + this_player () -> query_name ()
       + " drops out of the sky and into the mud.\n", this_player ());
  write ("SPLUT! You dive headlong into the mud!\n");
}

#define ESCORYN_DIRS ({ ES_TOWNDIR, ES_ROADDIR })

#define VILLAGE_ROOMS ({ \
"room/church",     "room/hump",       "room/vill_green", \
"room/vill_track", "room/vill_road1", "room/vill_road2", \
"room/vill_shore", "room/vill_jetty", "players/foslay/workroom", \
ES_BAYDIR"lighthouse", ES_ROADDIR"road1", ES_ROADDIR"road2", \
ES_ROADDIR"road3" })

flying_lesson (int flag)
{
  object *players;
  string room, path,
	 escoryn_msg, village_msg, bog_msg;
  int t;

  players = users ();

  if (flag == 0) {
    bog_msg = "You see " + this_player () -> query_name ()
    + " flying high above you.\n";

    escoryn_msg = "You see " + this_player () -> query_name ()
    + " flying high above the Great Bog, the swamp to the east.\n";

    village_msg = "You see " + this_player () -> query_name ()
    + " flying high above the Great Bog, the swamp to the west.\n";
  }
  else {
    bog_msg = escoryn_msg = village_msg = this_player () -> query_name ()
    + " has reached the highest point and is falling down again.\n";
  }

  for (t=0; t < sizeof (players); t++)
  {
    if (players [t] == this_player ())
      continue;

    if (!environment (players [t]))
      continue;

    room = file_name (environment (players [t]));
    path = implode (explode (room, "/") [0..<2], "/");

    if (path == "BOGDIR")
      tell_object (players[t], bog_msg);
    else if (member_array (room, VILLAGE_ROOMS) >= 0)
      tell_object (players[t], village_msg);
    else if (member_array (path, ESCORYN_DIRS) >= 0)
      tell_object (players[t], escoryn_msg);
  }
}
