#include <lib.h>
#include "ex.h"

inherit LIB_ROOM;
int pre_north();
int post_south();
int post_north();

void create()
{
    ::create();
    SetAmbientLight(30);
    SetShort( "pre/post exits and add/remove exits" );
    SetLong(@EndText
    There's a door to the north with a doorbell, and a blank
wall to the south.
-------------------------------------------------------------
This is an example room for using pre-exits and post-exits.
It also shows how to add & delete an exit from the room, and
use a temporary variable on a player.

There's a lever to pull and push, and a bell to ring.
Pull the lever out: create an exit to the south.
Push the lever in:  delete an exit to the south.
Ring the bell: allows you to go north.
When you go south, the exit to the south disappears.
-------------------------------------------------------------
EndText
    );

    SetExits( ([  
      ]));

    AddExit( "north", EXPATH + "exroom5", (: pre_north :));    

}

void init()
{
    ::init();
    add_action("aa_pull","pull");
    add_action("aa_push","push");
    add_action("aa_ring","ring");
}


int aa_pull(string str)
{
    if (str!="lever" && str!="lever out")
    {
	write( "Pull what?\n" );
	return 1;
    }
    /*  Now, we can find out if the lever has been already pulled
	  in one of two ways. 
	Method one: we test to see if the exit to the south is open.
	  Since pulling the lever does this, and the only way to
	  create that exit is pulling the lever -- this is a valid method.

	Method two: we use a variable and change it's value when the lever
	  is pushed or pulled.  Since we have a method that works without
	  using an additional variable, that is the method I'll pick here.
	  It will also show you how to query for an exit.

	Note:  GetExits() returns a mapping for all the exits in a room
	GetExit("dir") returns the value for that specific direction.
	if there is NOT an exit in that direction it will return UNDEFINED
	and can be detected using the ! operator. (! means 'not') 
	conversely, if GetExit("dir") is true, then there IS an exit
	to that direction.  Got it?  Good.
    */

    if ( GetExit("south") )
    {
	write("The lever is already pulled out!\n");
	return 1;
    }

    /*  If you don't know by now, this_player() indicates the player doing the actions
	  So when I do this_player()->GetName() it gives me the name of the player
	  who is doing the actions and allows me to tell the room who it is.
    */

    write( "You pull the lever and an invisible crack appears in the south wall. "+
      "A door slides open and there is a previously undetected exit." );
    say(this_player()->GetName() + " pulls the lever and an exit appears to the south.\n");

    //  AddExit() functions add an exit to the room.  Here, we added an exit and
    //  set up a (: functional :) to do close up the exit when they leave.

    AddExit( "south", EXPATH + "exroom3", (: post_south :) );
    SetObviousExits("n, s");
    return 1;
}


int aa_push(string str)
{
    if (str!="lever" && str!="lever in")
    {
	write( "Push what?\n" );
	return 1;
    }

    /*  Since there's more then one way for the exit to dissappear (see the post-exit
	function for south) and there may be more then one player wandering the halls
	we don't want to assume that 'this' player pushed the lever.  So we wouldn't
	say "You've already pushed the lever."
    */

    if ( ! GetExit("south") )
    {
	write( "The lever is pushed in as far as it will go.\n");
	return 1;
    }
    write( "You push the lever in and an unseen door slides shut in the south wall."+
      "The wall now appears solid and unpenatrable." );
    say(this_player()->GetName() + " pushes the lever and the south closes tight.\n");

    //  Now we remove the exit that was added earlier.

    RemoveExit("south");
    SetObviousExits("n");
    return 1;
}


int aa_ring(string str)
{
    if (str!="bell" && str!="doorbell" && str!="door bell")
    {
	write( "Ring what?\n" );
	return 1;
    }
    //if we only want to let them ring it once, we can check for the
    //temp var here.  This version will let them ring it many times.
    write("DONG!\nYou ring a doorbell! You are now admitted north.\n");
    say("DONG!  A doorbell rings.\n");
    this_player()->SetProperty("rung_bell", 1);
    return 1;
}


/* CODING STYLE 101
   Personally, I always put my post/pre exit functions right after create and 
   before the reset() or init() functions.  This makes them easy to find.
   Since they're MENTIONED in the create() I like to keep 'em close at hand.
   For the same reason I usually follow my init() with any add_actions that
   I've created.  I also preface my functions with an indicator saying what
   their purpose is.  I've chosen aa_ for add_actions an pe_ for pre or post
   exit functions.  OR i use pre_ or post_ when i have both going on.  This
   may not seem like a big deal in a little file, but when the file gets 
   huge, it helps to glance at a function and go: ah ha! this is a post_exit
   function.  or ah ha! this is an add_action or similarly: ah ha! this is
   not any specialized function so I must be calling it for some other reason.
   The order you write them in is a personal decision.  Just keep your
   create() function first on the list.
*/

//A return 0 in a pre-exit will prevent you from going that dir.
//A return 1 will allow you to go that dir.


int pre_north()
{
    if( !this_player()->GetProperty("rung_bell") )
    {
	write("Ring the doorbell first!\n");
	return 0;  
    }
    //  Now that the pre_north() function has done what it needs to do, we 
    //   will call the post_north() function here
    post_north();
    return 1;
}


int post_north()
{
    //might as well delete it, it's served its purpose.
    this_player()->RemoveProperty("rung_bell");
    return 1;
}


//We're going to delete the exit AFTER the player walks through
//  Because doing it in a pre_exit would be tatamount to slamming
//  a door in their face.  You wouldn't want to do that... would you?  :P


int post_south()
{
    write("You hear a noise and realize the wall has mysteriously closed.\n");
    say("You hear a noise and realize the wall has mysteriously closed.\n");
    this_player()->eventMoveLiving("/domains/examples/room/exroom3", "south", this_player()->GetName()+" enters.");
    RemoveExit("south");
    SetObviousExits("n");
}
