demon.c and demonfuncs.c - examples for course 09

[previous example] [course09] [Table of contents] [next example]
/* Filename      : demon.c
 * Description   : the demon summoned by blowing the horn
 *
 * written       : 05-10-1996 - Gunner
 * last modified : 28-05-1998 - Gunner
 * HTML-Version  : 06-02-2000 - Ghorwin
 */

#include <mudlib.h>
inherit I_MONSTER;

#define FUNC    "/doc/crashcourse/course09/demonfuncs"
#define CMDPATH "/doc/crashcourse/course06/com/"

create()
{
    ::create();
    set_name("iggiook");
    add_id(({"demon","evil demon","demon from hell","shadow","dark demon"}));
    set_short("A dark demon");
    set_long("A dark demon from hell. It looks more like a shadow "
        "than a living creature. It's probably not alive, anyways...\n");
    set_level(20);
    set_race("demon");
    set_hp(500+random(500));
    set_sp(500+random(500));
    set_al(-500);
    set_wc(30);
    set_ac(10);
    add_skill("vuln_cold",20);
    add_skill("vuln_magic",80);
    add_skill("vuln_acid",50);
    add_skill("prot_blunt",20);
    add_skill("prot_fire",80);
    add_skill("prot_slash",20);
    add_skill("prot_chop",20);
    add_skill("prot_pierce",20);

    add_cmdpath(CMDPATH);
    load_a_chat(20,({"!meteor",
                     "!cast fireball at",
                     "!cast electric storm at",
                     "!cast lightning bolt at",
                     "*scream",
                     "*grin evi",
                     "*frin evi"}));
  
    add_hook("__catch_tell",({FUNC,"demon_order"}),this_object());
    add_hook("__move_player",({FUNC,"demon_move"}),this_object());
    add_hook("__kill",({FUNC,"demon_kill"}));
    add_hook("__bdie",({FUNC,"demon_dies"}),this_object());
    replace_program(I_MONSTER);
}

demonfuncs.c


/* Filename      : demonfuncs.c
 * Description   : the functionfile for demon.c
 *
 * written       : 05-10-1996 - Gunner
 * last modified : 28-05-1998 - Gunner
 * HTML-Version  : 06-02-2000 - Ghorwin
 */

#include <mudlib.h>
#include "/doc/crashcourse/defs.h"
inherit I_DAEMON;

#define MAX_IDLETIME 60*5+random(60*5)

// A few global variables. For conveniency and efficiency

string name;
int    playerkills  = 0;
int    demonkills   = 0;
int    stay_here    = 0;


/* 
 * demon_order : Called by the __catch_tell in demon.c
 */
void
demon_order(object demon, string arg)
{
    string  line, 
            command, 
            enemy, 
            who;
    object  owner, 
            att, 
            notmaster;
    int     len;

    if (!name) return;

    if (strsrch(arg," tells you: ") == -1)
        return;     // Not a tell/order

    arg = replace_string(arg,"\n","");
    arg = replace_string(arg,"%^END%^","");

    if (sscanf(arg,"%s tells you: %s",who,line) != 2)
    { 
        tell_room(ENV(demon),"The demon looks kinda puzzled.\n");
        return;
    }

    owner = find_player(name);
    if (!owner) return;

    if (lower_case(who) != name)
    {
        notmaster = find_living(lower_case(who));
        if (!notmaster) return;
        tell_object(notmaster,"Iggiook replies: 'YOU ARE NOT MY MASTER!'\n");
        return;
    }

    if (sscanf(line,"%s %s",command,enemy) != 2)
    {
        command = line; enemy = 0;
    }

    switch (command)
    {
        case "report"   :
            tell_object(owner, "The demon tells you: 'I can report that I "
                "have taken " + demonkills + " lives, while you have "
                " taken " + playerkills + "!'\n");
            break;

        case "kill"     :
            if (!enemy)
            {
                tell_object(owner,"The demon tells you: 'Kill who, Master?'\n");
                return;
            }
            att = present(enemy, ENV(demon));
            if (!att)
            {
                tell_object(owner, "The demon tells you: 'I can't find " +
                    enemy + " anywhere, Master!'\n");
                return 1;
            }
            if (!living(att) || Q_NOFIGHT(att) || Q_NOFIGHT(ENV(demon)))
            {
                tell_object(owner, "The demon tells you: 'I can't do that, "
                    "Master!\n");
                return 1;
            }
            tell_object(owner,"The demon tells you: 'At once, Master!'\n");
            demon->do_attack(att);
            break;

        case "stay"     :
            tell_object(owner,"The demon tells you: 'I will stay right here, "
                "Master!'\n");
            stay_here = 1;
            break;

        case "follow"   :
            tell_object(owner,"The demon tells you: 'I will follow you to the "
                "end of the world, Master!'\n");
            stay_here = 0;
            break;

        case "stop"     :
            tell_object(owner,"The demon tells you: 'Yes, Master!'\n");
            demon->stop_fight();
            break;

        default         :
            tell_object(owner,"The demon tells you: 'I'm sorry, Master. I have "
                "only learned a few commands.'\nThe demon sobs for a "
                "while.\n'But, I do know how to 'stay', 'follow', "
                "'report', 'stop' and 'kill'!'\nThe demon frins evilly.\n");
            break;
    }
}


/* 
 * demon_move : Called by the __move_player hook in demon.c
 */
void
demon_move(object demon, string direction, object oldenv, object newenv)
{
    object owner;

    if (demon->query_chat_chance() <= 0)      // When the demon is called
    {
        name = demon->query_property("owner_name");
        demon->load_chat(10,({
            "*bow " + name,
            "*worship " + name,
            "*smile " + name,
            "The demon says: 'Now what, master?'\n",
            "The demon says: 'Can't we kill something, master?'\n",
            (:call_other, TO, "idle_check", demon:)}));
        tell_room(newenv,"The demon says: 'I have come to serve you, master. "
            "My name is Iggiook. Tell me what you want done and I "
            "will do it!'\n");
        owner = present(name,newenv);
        if (!owner)
        {
            demon->destroy();                    // Something went wrong...
            return;
        }
        owner->add_hook("__move_player",({TO, "player_moves"}));
        owner->add_hook("__kill",({TO, "player_kills"}));
        owner->add_hook("__notify_attack",({TO, "player_attacked"}));
        owner->add_hook("__bdie",({TO, "player_dies",owner}));
        owner->add_hook("__quit",(:call_other, TO, "player_quits",owner:));
    }
}

/* 
 * demon_kill : The demon kills something
 */
void
demon_kill(object enemy, object killer)
{
    tell_room(ENV(enemy),"The demon frins evilly. 'I did that.', it says...\n");
    demonkills++;
}

/* 
 * demon_dies : The demon is about to die
 */
int
demon_dies(object demon, object killer)
{
    object owner = find_living(name);

    tell_room(ENV(demon),"The demon cries out into the night. It's a desperate "
        "cry for help.\n");

    if (random(200) < demonkills)
    {
        tell_room(ENV(demon),"Its powerful lords of hell hear its cry and "
            "help their obidient servant!\n");
        demon->heal_self(5000);
        demonkills = 0;
        return 1;   // Igg survives!
    }

    tell_room(ENV(demon),"Its powerful lords of hell are silent...\n");
    if (!owner) return;

    owner->remove_hook("__move_player");
    owner->remove_hook("__kill");
    owner->remove_hook("__notify_attack");
    owner->remove_hook("__bdie");
    owner->remove_hook("__quit");
    return 0;       // Igg dies.. *sob*
}

/* 
 * player_moves : The player moves, time for the demon to follow. Or try at least
 */
void
player_moves(string direction, object oldenv, object newenv)
{
    object igg = find_living("iggiook");

    if (stay_here) return;              // STAY!

    if (!present(igg,oldenv)) return;   // Not inside the same room

    if (Q_NOPET(newenv))
    {
        tell_object(TP,"The demon tells you: 'Master! The lords tell me "
            "not to go in there!'\n");
        return;
    }

    igg->command(direction);
}

/* 
 * player_kill : The player kills something
 */
void
player_kills(object enemy, object killer)
{
    tell_object(killer,"The demon tells you: 'You did it, Master!'\n");
    playerkills++;
}

/* 
 * player_attacked : The player was attacked, help him/her/it
 */
void
player_attacked(object attacker)
{
    object igg = present("iggiook",ENV(attacker));
    if (!igg) return;

    if (igg->query_attack()) return;

    tell_room(ENV(attacker),"The demon shouts: 'I'll help you, Master!'\n");
    igg->do_attack(attacker,igg);
}

/* 
 * player_dies : The player is about to die. Help?
 */
int
player_dies(object player, object killer)
{
    if (random(300) < playerkills)
    {
        tell_object(PR,"The demon shouts: 'Master! The lords tells me you "
            "will not die yet. They must be pleased with you! "
            "But, they take the kills in return...'\n");
        player->heal_self(500);
        playerkills = 0;
        return 1;           // The player lives!
    }

    player->remove_hook("__move_player");
    player->remove_hook("__kill");
    player->remove_hook("__notify_attack");
    player->remove_hook("__bdie");
    player->remove_hook("__quit");
    return 0;               // Let the player die...
}

/* 
 * player_quits : The player quits! Bah.
 */
void
player_quits(object player)
{
    object igg = find_living("iggiook");
    if (!igg) return;       // Where did Igg go??
    tell_object(player,"The demon tells you: 'Are you leaving me, Master? But, "
        "how am I going to survive here with you? Well, I better "
        "go back then, I suppose... Goodbye, Master...'\n");
    player->remove_hook("__move_player");
    player->remove_hook("__kill");
    player->remove_hook("__notify_attack");
    player->remove_hook("__bdie");
    player->remove_hook("__quit");
}


/* 
 * idle_check : Don't idle, or Igg'll run off...
 */
void
idle_check(object demon)
{
    object owner = find_living(name);

    if (!owner) return;     // Eh? Now what?

    if (query_idle(owner) > MAX_IDLETIME)
    {
        tell_object(owner,"The demon tells you: 'I am bored, Master. I think "
            "I'll return to my lords of hell. Goodbye, Master...'\n");
        owner->remove_hook("__move_player");
        owner->remove_hook("__kill");
        owner->remove_hook("__notify_attack");
        owner->remove_hook("__bdie");
        owner->remove_hook("__quit");
        demon->destroy();
        return 1;
    }

    if (Q_NOMAGIC(ENV(demon)))
    {
        tell_room(ENV(demon),"The demon sighs: 'This place is no fun. It blocks "
            "my demonic powers...'\n");
        return 1;
    }

    if (Q_NOFIGHT(ENV(demon)))
    {
        tell_room(ENV(demon),"The demon sighs: 'This place is totally uncool.'\n");
        return 1;
    }
    return 1;
}