About the smartmonster - for version 0.4 (August 3, 1992)
-------------------------------------------------------

Written by Padrone, latest change of this file August 3, 1992.

This is a description of a monster object, "obj/smartmonster".

This smartmonster is (almost) backwards compatible
with the old /obj/monster, so you can replace most usages of
/obj/monster with /obj/smartmonster.

These functions, that were used to configure the old "obj/monster"
object, have been replaced, but can still be used in the compatible
version of the smartmonster:
    set_chance(int c)
    set_spell_mess1(string m)
    set_spell_mess2(string m)
    set_spell_dam(in d)
    load_chat(int chance, string *strs)
    load_a_chat(int chance, string *strs)
    set_match(object ob, mixed *func, mixed *type, mixed *match)
    set_aggressive(status a)
    set_alias(string a)
    set_alt_name(string a)
    set_whimpy()
(Later we might do something about move_at_reset, set_dead_ob,
and set_random_pick.)
This file contains a description on how to do corresponding things,
and more, in "obj/smartmonster".


Contents of this file
---------------------

    1. Some small changes
    2. A kinder, gentler aggressivity
    3. A more advanced (and correctly spelled) wimpy mode
    4. Simple chats, similar to "load_chat" in the old "/obj/monster"
    5. Responses to actions from players and monsters
    7. Special attacks and other things to do in a fight
    8. A function to call in each heart-beat
    9. The smartmonsters can be friends!
    10. Aliases
    11. The functions to call to configure the object
    12. Expanded stat format
    13. An example: Harry
    14. Incompatibilities with the old /obj/monster


1. Some small changes
---------------------

There are more (and better used) possible directions in the random move,
which is used both if the monster is trying to run away and if
"move_at_reset" has ben set.

To give the monster a soul, just call the function "set_soul".


2. A kinder, gentler aggressivity
---------------------------------

"set_aggressive" has ben replaced by "set_aggressivity",
which takes an argument between 0 (never attacks anything - corresponds
to the old set_aggressive(0)) and 100 (attacks everything it sees -
corresponds to the old set_aggressive(1)).
The attack decision is now dependent of the alignments and levels of both
the monster and the intended victim, and has an element of randomness.

By default monsters are totally peaceful.


3. A more advanced (and correctly spelled) wimpy mode
-----------------------------------------------------

The old "set_whimpy", which made the monster run away when its
hitpoints became low, has been replaced by "set_wimpyness", which takes
an argument between 0 (never run away) and 100 (run as soon as you are hurt).
The monster will run when it has less per cent hitpoints left then
the given argument.

To get the same effect as the old "set_whimpy()", use "set_wimpyness(20)".

By default monsters are totally un-wimpy, and will never run away.


4. Simple chats, similar to "load_chat" in the old "/obj/monster"
-----------------------------------------------------------------

Usage:
    set_chat_chance  CHAT-CHANCE
    set_chat_in_fight  FLAG
    add_chat  CHAT-MESSAGE
    set_chats  CHAT-MESSAGES-ARRAY

Examples:
    harry->set_chat_chance(2);
    harry->set_chat_in_fight(1);
    harry->add_chat("Harry says: What are you waiting for?\n");
    harry->add_chat("Harry says: Nice weather, isn't it?\n");
    smurf->set_chats(({ "The smurf smurfs.\n",
			"The smurf smurfs a smurf.\n" }));

After the above calls to harry, there is now a 2 percent chance at each
heartbeat (every two or three seconds), that one of the add_chat'ed strings
will be printed by Harry.
The reason for not having individual percentages for every string,
i. e. with the usage
    add_chat  CHAT-MESSAGE  [ CHANCE ]
is just because of efficiency. Maybe it can be changed later.


5. Responses to actions from players and monsters
-------------------------------------------------

Usage:
    add_response  ACTION  RESPONSE  [ PERSONAL-REPLY-MESSAGE ]  [ CHANCE ]
    set_responses  RESPONSE-ARRAY
    set_response_object  OBJECT

Or, in another way of putting it:
    add_response  ACTION  "REPLY-MESSAGE"  [ "PERSONAL-REPLY-MESSAGE" ]  [ CHANCE ]
    add_response  ACTION  "*FUNCTION-NAME"  [ CHANCE ]
    add_response  ACTION  "!COMMAND"  [ CHANCE ]
    add_response  ACTION  ARRAY-OF-RESPONSES  [ CHANCE ]

Examples of simple responses:
    harry->add_response("smiles happily", "Harry smiles happily.\n");
    harry->add_response("smiles happily", "Harry smiles happily.\n", 100);
    harry->add_response("smiles happily", "Harry smiles happily.\n", 0, 100);
    harry->add_response("smiles happily", "Harry smiles happily.\n",
			"Harry smiles at you.\n", 100);
    harry->add_response("says:", "Harry looks at the one who was talking.\n",
			"Harry looks at you.\n");
    harry->add_response("drops", "Harry says: Why did you drop that?\n");
    harry->add_response("drops", "Harry says: Why did you drop that?\n", 75);

If there is a second string, it is sent to the "opponent" instead of
the first message. If no CHANCE is given, or if it is 0, it will be set to 100.

Warning! Each matching response is tested against its chance in the order it
         was add_response'd, so if you set three responses, all with 50%
	 chance, their probabilities, if they match a certain action,
	 will be 50%, 25% and 12.5%!
	 This also applies to responses and attacks.

If the REPLY-MESSAGE starts with one of the characters '*' or a '!',
it is used as a function to call, or a command for the monster to execute.

Examples of advanced responses (function calls and commands):
    harry->set_response_object(this_object());
    harry->add_response("sings", "*handle_sing")
    harry->add_response("pukes", "*handle_puke", 0)
    harry->add_response("smiles happily", "*handle_happy_smile", 35)
    harry->add_response("smiles", "*handle_smile", 100)
    harry->add_response("kicks you", "!scream")

The function FUNCTION-NAME in the object OBJECT will be called with
three arguments: who, what and how.
If Harry now gets the message "Padrone smiles like a surgeon.\n",
the call will be:
    handle_smile("Padrone", "smiles", "like a surgeon.")

The RESPONSE can also be an array of responses:
    harry->add_response("bounce", ({ "!flip", "!smile", "!grin" }), 100);

The response is performed in the next heart beat (1-2 seconds later).
The value of this_player() will be the monster, so if you call a function
(with the "*FUNCTION-NAME" syntax), messages from say() will go to everyone
in the room except the monster, and write() will go to the monster itself.

Warning! Messages printed by write() in a response function or a command
	 will be seen by the monster (in the next heartbeat), and if they
	 are matched by a response there might be an infinite loop.

Often you want to use the name of the monster or player whose action we
are responding to. You can use the string "$OTHER", which will be
substituted with the other monster's or player's name. Example:
    harry->add_response("kicks you", "Harry glares at $OTHER.\n",
		        "Harry glares at you.\n");
The string "$LOWOTHER" will be substituted with the lower-case form of
the name.
"$OTHER" and "$LOWOTHER" also works in commands and function calls:
    harry->add_response("kicks you", "!kick $LOWOTHER");
    harry->add_response("kicks you", "*handle_kick_by_$LOWOTHER");


6. Responses to certain frequently used actions
-----------------------------------------------

Usage:
    set_say_handler  [ OBJECT  [ FUNCTION-NAME ] ]
    set_tell_handler  [ OBJECT  [ FUNCTION-NAME ] ]
    set_give_handler  [ OBJECT  [ FUNCTION-NAME ] ]
    set_give_money_handler  [ OBJECT  [ FUNCTION-NAME ] ]
    set_arrive_handler  [ OBJECT  [ FUNCTION-NAME ] ]
    set_leave_handler  [ OBJECT  [ FUNCTION-NAME ] ]

Examples:
    harry->set_say_handler();
    harry->set_tell_handler(this_object(), "handle_say_and_tell");
    harry->set_give_handler("players/ugh/centcomp", "got_something");

Whenever one of the actions happen (someone saying something, etc.), the
function FUNCTION-NAME in the object OBJECT will be called with  some useful
arguments. Default function names: "handle_say", "handle_tell", "handle_give",
"handle_give_money", "handle_arrive", "handle_leave".

The arguments that are sent are:
    1. the object that did something (if it wasn't possible to find this
       object, the function is not called - except in the case of leaving),
    2. the name of the player or monster that did it, and finally
    3a. the phrase that was said, or
    3b. the object (and it's name) that was given, or
    3c. the way someone arrived or left.

If we assume that the default function names are used, this might give
an idea of how the calls are made:
    handle_say(who_obj, who_string, phrase_string);
    handler_tell(who_obj, who_string, phrase_string);
    handle_give(who_obj, who_string, what_obj, what_string);
    handle_give_money(who_obj, who_string, number_of_coins);
    handle_arrive(who_obj, who_string, how_string);
    handle_leave(who_obj, who_string, how_string);

Don't forget that "handle_give" takes four arguments,
that the third argument to handle_give_money is an integer,
and that the first argument to handle_leave will be 0.
Also remember the difference from response functions (see above),
which are called with three strings as arguments: who, what and how.


7. Special attacks and other things to do in a fight
----------------------------------------------------

This is a replacement for both "load_a_chat" (attack chats)
and the "set_spell_mess1" functions:

Usage:
   add_attack  ATTACK-MESSAGE  [ PERSONAL-ATTACK-MESSAGE ]  MAX-DAMAGE  [ CHANCE ]

Examples:
   harry->add_attack("Harry says: Help, someone!\n", 0, 0, 10);
   harry->add_attack("Harry punched his opponents nose.\n",
		     "Harry punched your nose.\n", 2, 50);
   glumglot->add_attack("Glumglot casts a fireball.\n",
			"You are hit by a fireball.\n", 50, 10);
   glumglot->add_attack("Glumglot casts a fireball.\n", 50, 10);

"$OTHER" can be used in the attack messages:
   harry->add_attack("Harry punched $OTHER's nose.\n",
		     "Harry punched your nose.\n", 2, 50);


8. A function to call in each heart-beat
----------------------------------------

The smartmonster can be set up to call a function at every heartbeat
while it's in a fight, and another function at every heartbeat while
it's not in a fight.

Usage:
    set_fight_beat  [ OBJECT  [ FUNCTION-NAME ] ]
    set_peace_beat  [ OBJECT  [ FUNCTION-NAME ] ]

Examples:
    wizard->set_fight_beat(this_object(), "teleport_away");
    cow->set_peace_beat("players/grendel/room/meadow", "munch_some_hay");
    orc->set_fight_beat();

The function FUNCTION-NAME in the object OBJECT will be called
each heart-beat, in the case of fight_beat with the current enemy
as argument.

Default function names: "fight_beat" and "peace_beat".


9. The smartmonsters can be friends!
------------------------------------

Usage:
   add_friend  OBJECT-OR-NAME
   set_friends  ARRAY-OF-OBJECTS-OR-NAMES

Examples:
   wizard->add_friend("sheriff");
   orc1->add_friend(orc2);
   orc1->set_friends( ({ orc2, orc3, orc4 }) );

Friends will help each other in a fight, i. e. they will attack
the monster or player that their friends are fighting.


10. Aliases
-----------

A smartmonster can have any number of aliases.

Usage:
   add_alias  STRING
   set_friends  ARRAY-OF-STRINGS
Examples:
   arnold->set_aliases( ({ "hero", "big-guy", "muscle" }) );
   arnold->add_alias("terminator");


11. The functions to call to configure the object
-------------------------------------------------

These are the functions you should call to configure the monster.

First, call these three functions:

    set_name(string n)
    set_short(string sh)
    set_level(int l)

IT IS IMPORTANT that you call these functions FIRST,
and that you call set_name BEFORE you call set_short,
since they will set default values for some values.

Then, call any of these functions that you want.
It is strongly suggested that you always use at least set_long, set_al
and the gender functions (one of set_male, set_female and set_neuter)!

    set_aliases(string *all_aliases)
    add_alias(string str)
    set_race(string r)
    set_long(string lo)

    set_wc(int wc)
    set_ac(int ac)
    set_hp(int hp)
    set_ep(int ep)

    set_str(int i)
    set_int(int i)
    set_con(int i)
    set_dex(int i)

    set_al(int al)
    set_aggressivity(int a)
    set_wimpyness(int w)
    set_male()
    set_female()
    set_neuter()

    set_attacks(mixed *all_attacks)
    add_attack(string msg, mixed arg2, mixed arg3, mixed arg4)

    set_chats(string *all_chats)
    add_chat(string the_chat)
    set_chat_chance(int percentage)
    set_chat_in_fight(status f)

    set_responses(mixed *all_responses)
    add_response(string act, mixed response, mixed arg3, mixed arg4)
    set_response_object(mixed obj)

    set_say_handler(mixed obj, string fun)
    set_tell_handler(mixed obj, string fun)
    set_give_handler(mixed obj, string fun)
    set_give_money_handler(mixed obj, string fun)
    set_arrive_handler(mixed obj, string fun)
    set_leave_handler(mixed obj, string fun)

    set_fight_beat(object obj, string fun)
    set_peace_beat(object obj, string fun)

    set_friends(mixed *all_friends)
    add_friend(mixed the_name)

    set_soul()

    set_move_at_reset()
    set_random_pick(status r)
    set_init_ob(mixed ob)


12. Expanded stat format
------------------------

If you call show_stats() in a smartmonster, for example with the wizard
command "stat", you will see some additional smartmonster-specific data,
for example as in this output from "stat harry":

    Harry the affectionate
    level:  3
    coins:  0
    hp:     66 (max: 66)
    spell   66 (max: 0)
    ep:     1522
    ac:     0
    wc:     5
    carry:  0
    align:  50
    gender: male
    str: 3, int: 3, con: 3, dex: 3
    age:    2 seconds.
    Additional smartmonster data:
      chat_data: 10 chats, chat_chance: 2, chat_in_fight: 0
      say_handler: 'answer_say' in OBJ(room/vill_road2)
      tell_handler: 'answer_say' in OBJ(room/vill_road2)
      give_handler: 'handle_give' in OBJ(room/vill_road2)
      give_money_handler: 'handle_give_money' in OBJ(room/vill_road2)
      arrive_handler: 'say_hello' in OBJ(room/vill_road2)
      leave_handler: 'follow' in OBJ(room/vill_road2)
      handle_caught_texts = 1
      Waiting texts from catch_tell(): 0
      aggressivity: 0
      attack_data: 9 attacks
      friends: 0
      response_data: 12 responses, response_object = OBJ(room/vill_road2)
    Smartmonster responses:
      'sells': '*why_did' - 100%
      'attacks': '*why_did' - 100%
      'left the game': '*why_did' - 100%
      'takes': '*why_did' - 100%
      'drops': '*why_did' - 100%
      'is now level': '*how_does_it_feel' - 100%
      'falls down laughing': 'Harry looks at the one who laughed.\n'
        ('Harry looks at you.\n') - 100%
      'bounces': ['!flip', '!smile'] - 100%
      'sings': 'Harry says: You really have a nice voice!\n' - 50%
      'sings': 'Harry tries to sing too.\n' - 50%
      'sings': '!applaud' - 50%
      'smiles happily': 'Harry smiles happily.\n' - 100%


13. An example: Harry
---------------------

I have re-written /room/vill_road2.c (the room which defines Harry)
to use the smartmonster.


14. Incompatibilities with the old /obj/monster
-----------------------------------------------

In the old monster, when it called a function set up by "set_match",
the value of this_player() usually was the monster object, but
sometimes (rather randomly) it could be the object that sent the
string the monster reacted to. In the smartmonster, the value of
this_player() will always be the monster object.

If you have a randomly moving monster (move_at_reset or wimpy),
and rely on it going only in some directions, your code could fail.

The percentages for attack-chats will not be quite right.

If the monster object is inherited, and the functions in it
are called in non-standard ways, I don't know what will happen.
