Exemple #1
0
/**
 * Informs a player of what happened around the character.
 */
static void informPlayer(MapComposite *map, Character *p)
{
    MessageOut moveMsg(GPMSG_BEINGS_MOVE);
    MessageOut damageMsg(GPMSG_BEINGS_DAMAGE);
    const Point &pold = p->getOldPosition(), ppos = p->getPosition();
    int pid = p->getPublicID(), pflags = p->getUpdateFlags();
    int visualRange = Configuration::getValue("visualRange", 320);

    // Inform client about activities of other beings near its character
    for (BeingIterator i(map->getAroundBeingIterator(p, visualRange)); i; ++i)
    {
        Being *o = *i;

        const Point &oold = o->getOldPosition(), opos = o->getPosition();
        int otype = o->getType();
        int oid = o->getPublicID(), oflags = o->getUpdateFlags();
        int flags = 0;

        // Check if the character p and the moving object o are around.
        bool wereInRange = pold.inRangeOf(oold, visualRange) &&
                           !((pflags | oflags) & UPDATEFLAG_NEW_ON_MAP);
        bool willBeInRange = ppos.inRangeOf(opos, visualRange);

        if (!wereInRange && !willBeInRange)
        {
            // Nothing to report: o and p are far away from each other.
            continue;
        }


        if (wereInRange && willBeInRange)
        {
            // Send attack messages.
            if ((oflags & UPDATEFLAG_ATTACK) && oid != pid)
            {
                MessageOut AttackMsg(GPMSG_BEING_ATTACK);
                AttackMsg.writeShort(oid);
                AttackMsg.writeByte(o->getDirection());
                AttackMsg.writeByte(static_cast< Being * >(o)->getAttackType());
                gameHandler->sendTo(p, AttackMsg);
            }

            // Send action change messages.
            if ((oflags & UPDATEFLAG_ACTIONCHANGE))
            {
                MessageOut ActionMsg(GPMSG_BEING_ACTION_CHANGE);
                ActionMsg.writeShort(oid);
                ActionMsg.writeByte(static_cast< Being * >(o)->getAction());
                gameHandler->sendTo(p, ActionMsg);
            }

            // Send looks change messages.
            if (oflags & UPDATEFLAG_LOOKSCHANGE)
            {
                MessageOut LooksMsg(GPMSG_BEING_LOOKS_CHANGE);
                LooksMsg.writeShort(oid);
                Character * c = static_cast<Character * >(o);
                serializeLooks(c, LooksMsg, false);
                LooksMsg.writeShort(c->getHairStyle());
                LooksMsg.writeShort(c->getHairColor());
                LooksMsg.writeShort(c->getGender());
                gameHandler->sendTo(p, LooksMsg);
            }

            // Send direction change messages.
            if (oflags & UPDATEFLAG_DIRCHANGE)
            {
                MessageOut DirMsg(GPMSG_BEING_DIR_CHANGE);
                DirMsg.writeShort(oid);
                DirMsg.writeByte(o->getDirection());
                gameHandler->sendTo(p, DirMsg);
            }

            // Send damage messages.
            if (o->canFight())
            {
                Being *victim = static_cast< Being * >(o);
                const Hits &hits = victim->getHitsTaken();
                for (Hits::const_iterator j = hits.begin(),
                        j_end = hits.end(); j != j_end; ++j)
                {
                    damageMsg.writeShort(oid);
                    damageMsg.writeShort(*j);
                }
            }

            if (oold == opos)
            {
                // o does not move, nothing more to report.
                continue;
            }
        }

        if (!willBeInRange)
        {
            // o is no longer visible from p. Send leave message.
            MessageOut leaveMsg(GPMSG_BEING_LEAVE);
            leaveMsg.writeShort(oid);
            gameHandler->sendTo(p, leaveMsg);
            continue;
        }

        if (!wereInRange)
        {
            // o is now visible by p. Send enter message.
            MessageOut enterMsg(GPMSG_BEING_ENTER);
            enterMsg.writeByte(otype);
            enterMsg.writeShort(oid);
            enterMsg.writeByte(static_cast< Being *>(o)->getAction());
            enterMsg.writeShort(opos.x);
            enterMsg.writeShort(opos.y);
            switch (otype)
            {
            case OBJECT_CHARACTER:
            {
                Character *q = static_cast< Character * >(o);
                enterMsg.writeString(q->getName());
                enterMsg.writeByte(q->getHairStyle());
                enterMsg.writeByte(q->getHairColor());
                enterMsg.writeByte(q->getGender());
                serializeLooks(q, enterMsg, true);
            }
            break;

            case OBJECT_MONSTER:
            {
                Monster *q = static_cast< Monster * >(o);
                enterMsg.writeShort(q->getSpecy()->getType());
                enterMsg.writeString(q->getName());
            }
            break;

            case OBJECT_NPC:
            {
                NPC *q = static_cast< NPC * >(o);
                enterMsg.writeShort(q->getNPC());
                enterMsg.writeString(q->getName());
            }
            break;

            default:
                assert(false); // TODO
            }
            gameHandler->sendTo(p, enterMsg);
        }

        if (opos != oold)
        {
            flags |= MOVING_POSITION;
        }

        // Send move messages.
        moveMsg.writeShort(oid);
        moveMsg.writeByte(flags);
        if (flags & MOVING_POSITION)
        {
            moveMsg.writeShort(opos.x);
            moveMsg.writeShort(opos.y);
            // We multiply the sent speed (in tiles per second) by ten
            // to get it within a byte with decimal precision.
            // For instance, a value of 4.5 will be sent as 45.
            moveMsg.writeByte((unsigned short) (o->getSpeed() * 10));
        }
    }

    // Do not send a packet if nothing happened in p's range.
    if (moveMsg.getLength() > 2)
        gameHandler->sendTo(p, moveMsg);

    if (damageMsg.getLength() > 2)
        gameHandler->sendTo(p, damageMsg);

    // Inform client about status change.
    p->sendStatus();

    // Inform client about health change of party members
    for (CharacterIterator i(map->getWholeMapIterator()); i; ++i)
    {
        Character *c = *i;

        // Make sure its not the same character
        if (c == p)
            continue;

        // make sure they are in the same party
        if (c->getParty() == p->getParty())
        {
            int cflags = c->getUpdateFlags();
            if (cflags & UPDATEFLAG_HEALTHCHANGE)
            {
                MessageOut healthMsg(GPMSG_BEING_HEALTH_CHANGE);
                healthMsg.writeShort(c->getPublicID());
                healthMsg.writeShort(c->getHealth());
                gameHandler->sendTo(p, healthMsg);
            }
        }
    }

    // Inform client about items on the ground around its character
    MessageOut itemMsg(GPMSG_ITEMS);
    for (FixedActorIterator i(map->getAroundBeingIterator(p, visualRange)); i; ++i)
    {
        assert((*i)->getType() == OBJECT_ITEM ||
               (*i)->getType() == OBJECT_EFFECT);

        Actor *o = *i;
        Point opos = o->getPosition();
        int oflags = o->getUpdateFlags();
        bool willBeInRange = ppos.inRangeOf(opos, visualRange);
        bool wereInRange = pold.inRangeOf(opos, visualRange) &&
                           !((pflags | oflags) & UPDATEFLAG_NEW_ON_MAP);

        if (willBeInRange ^ wereInRange)
        {
            switch (o->getType())
            {
            case OBJECT_ITEM:
            {
                Item *o = static_cast< Item * >(*i);
                if (oflags & UPDATEFLAG_NEW_ON_MAP)
                {
                    /* Send a specific message to the client when an item appears
                       out of nowhere, so that a sound/animation can be performed. */
                    MessageOut appearMsg(GPMSG_ITEM_APPEAR);
                    appearMsg.writeShort(o->getItemClass()->getDatabaseID());
                    appearMsg.writeShort(opos.x);
                    appearMsg.writeShort(opos.y);
                    gameHandler->sendTo(p, appearMsg);
                }
                else
                {
                    itemMsg.writeShort(willBeInRange ? o->getItemClass()->getDatabaseID() : 0);
                    itemMsg.writeShort(opos.x);
                    itemMsg.writeShort(opos.y);
                }
            }
            break;
            case OBJECT_EFFECT:
            {
                Effect *o = static_cast< Effect * >(*i);
                o->show();
                // Don't show old effects
                if (!(oflags & UPDATEFLAG_NEW_ON_MAP))
                    break;
                Being *b = o->getBeing();
                if (b)
                {
                    MessageOut effectMsg(GPMSG_CREATE_EFFECT_BEING);
                    effectMsg.writeShort(o->getEffectId());
                    effectMsg.writeShort(b->getPublicID());
                    gameHandler->sendTo(p, effectMsg);
                } else {
                    MessageOut effectMsg(GPMSG_CREATE_EFFECT_POS);
                    effectMsg.writeShort(o->getEffectId());
                    effectMsg.writeShort(opos.x);
                    effectMsg.writeShort(opos.y);
                    gameHandler->sendTo(p, effectMsg);
                }
            }
            break;
            default:
                break;
            } // Switch
        }
    }

    // Do not send a packet if nothing happened in p's range.
    if (itemMsg.getLength() > 2)
        gameHandler->sendTo(p, itemMsg);
}