spellmonster

obj
OBJECT
	/obj/monster/spellmonster


SYNOPSIS
	inherit "/obj/monster/spellmonster";

	#include <spellmonster.h>


LAST UPDATE
	Thragor, 07-Apr-97, 21:30 MET


DESCRIPTION
	You need a monster, which can cast fireballs, scare players or
	just give a message to its enemies, like 'Hartward laughs
	scornfully at Thragor.'?
	Then /obj/monster/spellmonster is the right choice :-)

	If you find (protected) below a function this means, that the
	function is only available to the monster, which inherits the
	spellmonster. A call_other() to this function won't work.

	The functions to configure the spellmonster:

	  mapping P_SPELLS "Spells"
	    A mapping of all spells looking like this:
	      ([<id>:([<spell-components>])]).
	    The <spell-components> are described in AddSpell() (see
	    below).
	
	  int P_CAST_CHANCE "CastChance"
	    The chance that a spell gets cast during an
	    attack-phase. Default value is 20.

	The main function to configure the spellmonster is:

	mapping AddSpell(string id,int mindam,int maxdam)
	mapping AddSpell(void|int|string id,mapping props)
	  The first version is the most basic one. You may use this,
	  if the monster shall just cast a simple fireball:
	    AddSpell("fireball",5,15);
	    The player who got hit by the fireball, will get the
	  message 'Hartward casts a fireball at you.' and receive
	  about 10 points of damage. The default damagetype is
	  DT_FIRE, so if you add a spell like this, the damage is
	  always done as DT_FIRE.

	  Much more work, and much more effect has the second version.
	  You don't need to specify the <id>, if you don't want to
	  access this spell later to modify it. In this case an
	  integer value will be taken as id.
	  <props> is a mapping of properties taken from
	  <spellmonster.h>. Here's the description of the properties:

	    closure S_CHECKFUN "CheckFunction"
	      This is a function called to evaluate if the spell might
	       be possibly cast. As this is only a test, you don't
	       have to perform any actions, as the spell which will be
	       cast might be another one.
	       Example:
	         Hartward might have too few spellpoints during a
	         fight to cast any other spell. In this case Hartward
	         should cast a spell, which sucks spellpoints from all
	         livings in the room. The S_CHECKFUN returns true,
	         when the spellpoints of Hartward are below 30.
	       May later be modified with the function
	         void SetSpellCheck(int|string id,closure f).

	    closure S_FUN "Function"
	      This function will be called before the spell gets
	      actually executed. As parameter the functions gets the
	      mapping which contains all data about the spell and a
	      reference to the victims-array. The victims-array is 0
	      on call. If it is 0 after the call the victims will be
	      evaluated with GetVictims(). If the function returns 0,
	      no further actions will be performed.
	      If the function returns a (the?) mapping which describes
	      the spell, this spell will be executed. This is
	      e. g. useful, if you want to modify something in the
	      mapping before it gets executed.
	      Example: Spell "sucksp" in Hartward.
	      May later be modified with the function
	        void SetSpellFun(int|string id,closure f).

	    int S_CHANCE "Chance"
	      The chance, that if a spell gets casted, THIS spell gets
	      casted. To ease reading the code, it's useful to try to
	      give the chance in percentage, but you don't need
	      to. You may also give all lets say 4 spells a chance of
	      one. As a result all spells will be taken with a chance
	      of 25%.
	      May later be modified with the function
	        void SetSpellChance(int|string id,int c).

	    int S_COMBAT_DELAY "CombatDelay"
	      If the spell got cast the monster will stop all combat
	      actions for S_COMBAT_DELAY heartbeats (i. e. rounds).
	      May later be modified with the function
	        void SetSpellCombatDelay(int|string id,int d).

	    int S_DELAY "Delay"
	      Different from S_COMBAT_DELAY this is the time in
	      heartbeats the monster has to wait before it can cast
	      THIS spell again.
	      May later be modified with the function
	        void SetSpellDelay(int|string id,int d).

	    status S_SIMULT "Simultaneously"
	      This flag decides if the spell might be cast together
	      with a physical attack of a player, or, if the spell got
	      cast, that no other combat actions should be done.
	      May later be modified with the function
	        void SetSpellSimult(int|string id,status s).

	    int S_VICTIMS "Victims"
	      The maximum number of victims this spell might aim at. A
	      value of 30 should hit all current enemies. If the value
	      is negative, all livings in the room will be affected by
	      the spell if they are no ghosts and there HP are equal
	      or greater than 0.
	      May later be modified with the function
	        void SetSpellVictims(int|string id,int v).

	    int S_DAMTYPE "DamType"
	      The type of damage (taken from <combat.h>) of which the
	      spell is. This might be any of the conventional damage
	      types or of the magic ones.
	      May later be modified with the function
	        void SetSpellDamType(int|string id,int d).

	    int S_MINDAM "MinDamage"
	      The minimum damage done by the spell.
	      May later be modified with the function
	        void SetSpellMinDam(int|string id,int d).

	    int S_MAXDAM "MaxDamage"
	      The maximum damage of the spell. If S_MAXDAM is 0, no
	      damage will be done at all, i. e. Defend() won't be
	      called in the opponent, so casting this spell, doesn't
	      automatically make the victim an enemy of the monster.
	      This is e. g. useful if you just want to give a message
	      to the room.
	      Example: Spell "comment" in Hartward.
	      May later be modified with the function
	        void SetSpellMaxDam(int|string id,int d).

	    int S_SP "Spellpoints"
	      Of course casting a spell should cost spellpoints for
	      the monster, too. If it can't afford the spellpoints,
	      the spell won't be cast.
	      May later be modified with the function
	        void SetSpellSP(int|string id,int s).

	    int S_HP "Hitpoints"
	      Ever heard of blood-magic? Now the spellmonster can do
	      this, too. The S_HP set here will be taken from the
	      actual hitpoints of the monster. If this would reduce
	      the hitpoints below the whimpy-value set for the
	      monster, the spell won't be cast.
	      May later be modified with the function
	        void SetSpellHP(int|string id,int s).

	  Now something more complicate about the properties: The
	  message-system. It should guarantee a very good handling for
	  the player, so that (s)he may see what the monster does.
	  All messages are parsed through parse_string():

	    string parse_string(string str)
	    (protected)
	      If the string is empty (=="") the string will be
	      returned unmodified. This is needed for 'empty'
	      messages.
	      The string will be parsed through process_string and
	      then automatically wrapped. So you don't need to enter
	      newlines, if you don't want to force them to appear at a
	      certain position. If the newline at the end of the
	      string is missing, a newline will be appended.

	    string|string* S_GLOBAL_ENVMSG "GlobalEnvMsg"
	      All players in the room will get the message, before the
	      spell gets actually cast. If the spell targets more than
	      one enemy, functions like VicName() (see below) return
	      appropriate values, in this special case a list of all
	      names: "Thragor, Tnt and Guest1".
	      If S_GLOBAL_ENVMSG is a string, every living in the room
	      will receive the same message. If S_GLOBAL_ENVMSG is an
	      array of two strings, the first entry will be printed to
	      all livings which can see, the second entry to all which
	      can't.

	    mapping S_ENVMSG "EnvironmentMessage"
	      The mapping may contain two entries:
	        string|string* MSG_NORMAL "Normal"
	          This message will be printed to the environment of
	          the current victim (in this case only one victim at
	          a time). If the entry is an array the first entry
	          will be printed to all who can see, the second one
	          to all those who can't.
	        string|string* MSG_DEAD "Dead"
	          If the victim is dead, after damage got dealt, this
	          message will be printed. The entry follows the same
	          rules as MSG_NORMAL.

	    mapping S_VICMSG "VictimMessage"
	      The mapping may contain two entries:
	        string|string* MSG_NORMAL "Normal"
	          This message will be printed to the current victim
	          (in this case only one victim at a time). If the
	          entry is an array the first entry will be printed to
	          all who can see, the second one to all those who
	          can't.
	        string|string* MSG_DEAD "Dead"
	          If the victim is dead, after damage got dealt, this
	          message will be printed. The entry follows the same
	          rules as MSG_NORMAL.

	For the messages, several functions are defined to be parsed
	through process_string. As all messages are 'bare',
	i. e. nothing is appended to them automatically, you have to
	add the name of the monster, too, if you want it to be
	mentioned in the message. These are the functions:

	  string build_list(string* strs)
	  (protected)
	    This is internally used, to get a list of names. If
	    there's only one entry in strs, this entry will be
	    returned, otherwise a list like:
	      "Thragor, Tnt and Guest1"
	    will be returned.

	  string MyName(void|string cap)
	    Returns the name of the spellmonster. If called with
	    <cap> set, the name will be returned capitalized.
	    Example:
	      "@@MyName@@" will be replaced by "a dragon"
	      "@@MyName|1@@" will be replaced by "A dragon"

	  string MyPronoun(void|string cap)
	    Returns the pronoun of the spellmonster. If called with
	    <cap> set, the pronoun will be returned capitalized.
	    Example:
	      "@@MyPronoun@@" will be replaced by "he"
	      "@@MyPronoun|1@@ will be replaced by "He"

	  string MyPossessive(void|string cap)
	    Returns the possessive pronoun of the spellmonster. If
	    called with <cap> set, the possessive pronoun will be
	    returned capitalized.
	    Example:
	      "@@MyPossessive@@" will be replaced by "his"
	      "@@MyPossessive|1@@" will be replaced by "His"

	  string MyObjective(void|string cap)
	    Returns the objective pronoun of the spellmonster. If
	    called with <cap> set, the objective pronoun will be
	    returned capitalized.
	    Example:
	      "@@MyObjective@@" will be replaced by "him"
	      "@@MyObjective|1@@" will be replaced by "Him"

	  string MyGenitive(void|string cap)
	    Returns the name with the correct genitive ending. If
	    called with <cap> set, the name will be returned
	    capitalized.
	    Example:
	      "@@MyGenitive@@" will be replaced by "a dragon's"
	      "@@MyGenitive|1@@" will be replaced by "A dragon's"

	  string VicName(void|string cap)
	    If called with S_GLOBAL_ENVMSG (see above) this returns a
	    list of all victims (like "Thragor, Tnt and Guest1")
	    otherwise only the name of the current victim. If called
	    with <cap> set, the first name will be returned capitalized.
	    Example:
	      "@@VicName@@" will be replaced by
	                    "a cat, Thragor and a familiar"
	      "@@VicName|1@@" will be replaced by
	                      "A cat, Thragor and a familiar"

	  string VicPronoun(void|string cap)
	    Returns the pronoun of the victim. If called in
	    S_GLOBAL_ENVMSG and several victims are effected "they"
	    will be returned. If called with <cap> set, the pronoun
	    will be returned capitalized.
	    Example:
	      "@@VicPronoun@@" will be replaced by "he"
	      "@@VicPronoun|1@@" will be replaced by "He"

	  string VicPossessive(void|string cap)
	    Returns the possessive pronoun of the victim. If called in
	    S_GLOBAL_ENVMSG and several victims are effected "their"
	    will be returned. If called with <cap> set, the possessive
	    pronoun will be returned capitalized.
	    Example:
	      "@@VicPossessive@@" will be replaced by "his"
	      "@@VicPossessive|1@@" will be replaced by "His"

	  string VicObjective(void|string cap)
	    Returns the objective pronoun of the victim. If called in
	    S_GLOBAL_ENVMSG and several victims are effected "their"
	    will be returned. If called with <cap> set, the objective
	    pronoun will be returned capitalized.
	    Example:
	      "@@VicObjective@@" will be replaced by "him"
	      "@@VicObjective|1@@" will be replaced by "Him"

	  string VicGenitive(void|string cap)
	    Returns the name(s) of the victim(s) appended with the
	    correct genitive ending. If called with <cap> set, the
	    first name will be returned capitalized.
	    Example:
	      "@@VicGenitive@@" will be replaced by
	                    "a cat's, Thragor's and a species'"
	      "@@VicGenitive|1@@" will be replaced by
	                      "A cat's, Thragor's and a species'"

	  string VicS(string verb,void|string cap)
	    This returns either the plural form of the verb or the
	    normal form of the verb depending on the amount of
	    enemies. This is only useful to call in S_GLOBAL_ENVMSG,
	    as otherwise there's always only one victim.
	    As verb you should give the plural form.
	    If <cap> is set, the verb is returned capitalized.
	    Example:
	      "@@VicS|are@@"
	        1 victim -> "is"
	        2 victims -> "are"
	      "@@VicS|feed@@"
	        1 victim -> "feeds"
	        2 victims -> "feed"
	      "@@VicS|are|1@@"
	        1 victim -> "Is"
	        2 victims -> "Are"
	      "@@VicS|feed|1@@"
	        1 victim -> "Feeds"
	        2 victims -> "Feed"

	That's all about the messages. For the message-system two
	functions are used, which might be useful for you, too:
	  object *SetVictims(object *v)
	  object *QueryVictims()
	    This returns all actual victims of the spell. During
	    S_FUN, this entry is still 0. Afterwards it will contain
	    all victims until the victims are handled one by one,
	    i. e. S_GLOBAL_ENVMSG and get_damage() (see below) might
	    query all victims. Afterwards QueryVictims() will always
	    return only one victim, or 0 if the spell got cast.

	Last part of the description are the internal functions (which
	I haven't mentioned yet):

	int get_free_id()
	(protected)
	  Returns the first integer id, which isn't used yet (0 if no
	  integer values have been used yet.

	status check_cast(int|string id)
	(protected)
	  Checks whether a spell might be cast or not, i. e.: The
	  spell mustn't be delayed (counter will be decreased), the
	  monster has to have enough spell- and hitpoints to cast and
	  if all of this got passed, the S_CHECKFUN (see above) is
	  called, whether to execute the spell or not.
	  This is just used to get the spells, the monster might
	  possibly cast this turn! Not to get the spell, which the
	  monster will cast.

	int|string get_spell()
	(protected)
	  Returns the id of a spell, which shall be cast. The chance
	  check is done in here, as well as check_cast() (see above)
	  is called to evaluate the spells, which might be cast.

	int get_damage(object victim,int mindam,int maxdam)
	(protected)
	  Returns the damage, the victim will receive. In the default
	  version <victim> is not used, but if you e. g. want to
	  reduce the damage done to demons, you might check this
	  inside here.

	status valid_victim(object victim)
	  Returns true, if the spell might take effect on this
	  victim. Default is to check if the victim is a ghost or
	  if it has less than 0 hitpoints. In this case false (==0) is
	  returned.

	object *GetVictims(int nr_victims,
	                   void|status check_repulse,
	                   void|int damtype,
	                   void|mixed spell_id)
	  This function is used to evaluate the victims which will be
	  effected by the spell. By default it is called from
	  CastSpell() where the arguments contain the following:
	    nr_victims:    value from S_VICTIMS
	    check_repulse: true (1)
	    damtype:       value from S_DAMTYPE
	    spell_id:      the key-id of the spell

	status CastSpell(int|string id)
	  Now cast the spell! If 0 is returned, a physical attack
	  might take place, too. This is the order of the things which
	  will be done:
	    1. Check S_FUN (see above).
	    2. If S_FUN returned 0, abort.
	    3. Set the combat delay of the monster.
	    4. If the spell has S_DELAY set, add the spell to the
	       delayed-list.
	    5. Reduce the spellpoints.
	    6. Reduce the hitpoints.
	    7. Evaluate all victims.
	    8. Set the victims (SetVictims()).
	    9. Get the damage for each of the victims calling
	       get_damage() (see above).
	   10. Show S_GLOBAL_ENVMSG to the environment.
	   11. Now go through all victims and damage them...
	      a) Set the victims to the actual victim.
	      b) Print MSG_NORMAL to the victim.
	      c) Print MSG_NORMAL to the environment.
	      d) Do the damage to the player.
	      e) If player died:
	        I) Print MSG_DEAD to the victim.
	        II) Print MSG_DEAD to the environment.
	   12. Set the victims to 0.
	   13. Return the entry of S_SIMULT.

	void Attack()
	  Do the actual casting/attack. If CombatDelay is set, no
	  spell will be cast. Then the CastChance (see SetCastChance
	  above) is checked to random(100)+1.
	  If no spell got cast, or CastSpell() (see above) returned 0,
	  perform the physical attack.

	int create()
	  As /std/npc, create returns 1, if we're configuring the
	  blueprint. The CastChance will be set to default 20 and the
	  spellmonster will be registered (to ease update of the
	  spellmonster).


EXAMPLE
	/d/archwiz/common/monster/hartward.c


INHERITANCE TREE
	obj/monster/spellmonster
	  `-std/npc


SEE ALSO
	npc(S)