예제 #1
7
/* Melnorme strategy:
      - Wander around continuously until hero comes near
      - When hero is in room stop and turn purple
      - When hero left the room start to wander and turn green

   Returns ms elapsed, -2 if the monster dies.
*/
int
shMonster::doMelnorme ()
{
    int elapsed;
    int result = -1;
    int retries = 3;
    int myRoom = Level->getRoomID (mX, mY);

    while (-1 == result) {
        if (!retries--) {
            return 200;
        }

        /* Melnorme have no designated shop. They are willing to trade
           if you enter their room. This also allows them to relocate. */
        if (Level->getRoomID (Hero.mX, Hero.mY) == myRoom and
            Level->getRoomID (mX, mY) != 0)
        {
            if (mGlyph.mColor == kGreen and !isHostile ()) {
                /* Greet hero who just entered the room. */
                if (Hero.tryToTranslate (this)) {
                    char *buf = GetBuf ();
                    int rnd;
                    switch (RNG (3)) {
                    case 0: /* hello, heroname/title/racename */
                        rnd = RNG (4);
                        strncpy (buf, rnd == 0 ? Hero.mName :
                                      rnd == 1 ? Hero.mProfession->mName :
                                      rnd == 2 ? Hero.getTitle () :
                                                 Hero.myIlk ()->mName, SHBUFLEN);
                        if (rnd == 0) buf[0] = toupper (buf[0]);
                        break;
                    case 1: /* hello, heroname the Janitor */
                        snprintf (buf, SHBUFLEN, "%s the %s", Hero.mName,
                                  !RNG (3) ? Hero.mProfession->mName :
                                  !RNG (2) ? Hero.getTitle () :
                                             Hero.myIlk ()->mName);
                        buf[0] = toupper (buf[0]);
                        break;
                    case 2: /* hello, earthling Detective */
                        snprintf (buf, SHBUFLEN, "%s %s", Hero.myIlk ()->mName,
                                  !RNG (2) ? Hero.mProfession->mName :
                                             Hero.getTitle ());
                        break;
                    }

                    switch (RNG (4)) {
                    case 0:
                        I->p ("I bid you a formal welcome, %s.", buf); break;
                    case 1:
                        I->p ("Hello, %s.", buf); break;
                    case 2:
                        I->p ("How nice to see you, %s.", buf); break;
                    case 3: /* Use just the capitalized name because
                               greetings could be too long otherwise. */
                        strncpy (buf, Hero.mName, SHBUFLEN);
                        buf[0] = toupper (buf[0]);
                        I->p ("I had itchy pods recently, %s"
                              ", and here you are!", buf);
                        break;
                    }
                } else {
                    I->p ("%s mumbles something in coarse voice.", THE (this));
                }
            }
            mGlyph.mColor = kMagenta;
            mGlyph.mTileX = 3;

            /* Hero was greeted properly. Is this first encounter? */
            if (!Hero.getStoryFlag ("Met Melnorme")) {
                Hero.setStoryFlag ("Met Melnorme", 1);
                I->p ("Press '%s' to request services.",
                    I->getKeyForCommand (shInterface::kPay));
            }
        } else {
            mGlyph.mColor = kGreen;
            mGlyph.mTileX = 2;
        }

        switch (mTactic) {

        case kNewEnemy:
            mStrategy = kWander;
            mTactic = kNewEnemy;
            mGlyph.mColor = kNavy;
            mGlyph.mTileX = 4;
            return doWander ();
        case kMoveTo:
            result = doMoveTo ();
            continue;
        case kReady:
            /* Usually stay where you are but occassionally
               move to new square inside this room. */
            if (myRoom and !RNG (6)) {
                mDestX = RNG (mMelnorme.mSX, mMelnorme.mEX);
                mDestY = RNG (mMelnorme.mSY, mMelnorme.mEY);
                if (!mLevel->isOccupied (mDestX, mDestY)) {
                    elapsed = doQuickMoveTo ();
                    if (-1 == elapsed) elapsed = 800;
                    return elapsed;
                }
                return RNG (600, 1000); /* Path blocked. Wait. */
                /* !myRoom == Warp out of corridors eagerly. */
            } else if ((!myRoom or !RNG (40)) and
                       mGlyph.mColor == kGreen)
            {
                int newx = mX, newy = mY, tries = 3;
                while (tries--) {
                    mLevel->findUnoccupiedSquare (&newx, &newy);
                    if (!mLevel->isOccupied (newx, newy) and
                        !mLevel->isInShop (newx, newy) and
                        /* Do not accept corridors. */
                        (myRoom = Level->getRoomID (newx, newy)))
                    {
                        transport (newx, newy, 100, 1);
                        /* Update location data. */
                        Level->getRoomDimensions (myRoom,
                            &mMelnorme.mSX, &mMelnorme.mSY,
                            &mMelnorme.mEX, &mMelnorme.mEY);
                        /* Exclude walls from room coordinates. */
                        ++mMelnorme.mSX; ++mMelnorme.mSY;
                        --mMelnorme.mEX; --mMelnorme.mEY;
                        return FULLTURN;
                    }
                }
                return FULLTURN;
            } else {
                return FULLTURN;
            }
        default:
            mTactic = kReady;
            debug.log ("Unexpected Melnorme tactic!");
        }
    }

    return FULLTURN;
}
예제 #2
0
int BasicMonster::action()
{
	if ((usesMeleeWeapons() || usesRangedWeapons()) && inventory.size() > 0)
	{
		useBestWeapon();
	}
	int time;
	bool seen = seePlayer();
	if (shouldFlee())
	{
		time = doFlee();
		if (time > 0) return time;
	}
	if (attitude == ATTITUDE_HOSTILE && seen)
	{
		int sqdist = Point::sqlen(world.player->getCreature()->getPos() - position);
		Weapon* weapon = getMainWeapon();
		if (weapon == NULL) weapon = &baseWeapon;
		int range = weapon->getRange();

		// Ranged attack
		if (range > 1 && sqdist <= range*range)
		{
			time = doRangedAttack(weapon);
			if (time > 0) return time;
		}

		// Special attacks (e.g. dragon breath)
		time = doSpecialAttack();
		if (time > 0) return time;

		// Melee attack
		if (sqdist <= 2)
		{
			time = doMeleeAttack(weapon);
			if (time > 0) return time;
		}

		// Run towards player / tactical movement
		time = doChargePlayer();
		if (time > 0) return time;
	}

	// Random walk, search for items, etc.
	time = doWander();
	return time > 0 ? time : 10;
}
예제 #3
0
/* doctor strategy:
     wait around for hero to request services;
     occasionally advertise

   returns ms elapsed, -2 if the monster dies
*/
int
shMonster::doDoctor ()
{
    int elapsed;
    int res = -1;
    int retry = 3;

    while (-1 == res) {
        if (!retry--) {
            return 200;
        }

        switch (mTactic) {

        case kNewEnemy:
            mStrategy = kWander;
            mTactic = kNewEnemy;
            return doWander ();
        case kMoveTo:
            res = doMoveTo ();
            continue;
        case kReady:
            if (Level->getRoomID (mX, mY) != mDoctor.mRoomID) {
                /* somehow, we're not in our hospital! */
                mDestX = mDoctor.mHomeX;
                mDestY = mDoctor.mHomeY;

                if (setupPath ()) {
                    mTactic = kMoveTo;
                    continue;
                } else {
                    return 2000;
                }
            }

            if (canSee (&Hero) and
                mDoctor.mRoomID == Level->getRoomID (Hero.mX, Hero.mY))
            {
                if (0 == RNG (12)) {
                    /* move to an empty square near the home square */
                    mDestX = mDoctor.mHomeX;
                    mDestY = mDoctor.mHomeY;
                    if (!mLevel ->
                        findAdjacentUnoccupiedSquare (&mDestX, &mDestY))
                    {
                        elapsed = doQuickMoveTo ();
                        if (-1 == elapsed) elapsed = 800;
                        return elapsed;
                    }
                    return RNG (300, 1000); /* nowhere to go, let's wait... */
                } else if (0 == RNG (50)) {
                    const char *quips[] = {
                        "\"Dammit, %s! I'm a docbot, not %s!\"",
                        "\"Your second amputation is half off!\"",
                        "\"Galaxy-class health care services!\"",
                        "\"I've been through much experience, you're dealing with an expert!\""
                    };
                    const unsigned int NUMQUIPS = sizeof (quips) / sizeof (char *);
                    const char *nouns[] = {
                        "a magician",
                        "a psychiatrist",
                        "a bartender",
                        "a bricklayer",
                        "a mechanic",
                        "a priest",
                        "a lawyer",
                        "a prostitute",
                        "a toaster oven",
                        "a warbot"
                    };
                    const unsigned int NUMNOUNS = sizeof (nouns) / sizeof (char *);
                    if (Hero.tryToTranslate (this)) {
                        I->p (quips[RNG (NUMQUIPS)],
                              Hero.mName, nouns[RNG (NUMNOUNS)]);
                        Hero.interrupt ();
                    }
                    return RNG (500, 1000);
                }
                return RNG (500, 1000);
            } else {
                return RNG (800, 1600);
            }
        case kFight:
        case kShoot:
            mTactic = kReady;
            debug.log ("Unexpected doctor tactic!");
        }
    }

    return RNG (300, 1000); /* keep on lurking */
}