#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Atlas::Objects::Operation; using Atlas::Objects::Root; using Atlas::Objects::Entity::Anonymous; using WFMath::TimeStamp; using namespace Atlas::Message; using Atlas::Objects::smart_dynamic_cast; namespace Eris { Avatar::Avatar(Account* pl, const std::string& entId) : m_account(pl), m_entityId(entId), m_entity(NULL), m_stampAtLastOp(TimeStamp::now()), m_lastOpTime(0.0) { m_view = new View(this); m_entityAppearanceCon = m_view->Appearance.connect(sigc::mem_fun(this, &Avatar::onEntityAppear)); m_router = new IGRouter(this); m_view->getEntityFromServer(""); m_view->getEntity(m_entityId); } Avatar::~Avatar() { m_account->internalDeactivateCharacter(this); delete m_router; delete m_view; } void Avatar::deactivate() { Logout l; Anonymous arg; arg->setId(m_entityId); l->setArgs1(arg); l->setSerialno(getNewSerialno()); getConnection()->getResponder()->await(l->getSerialno(), this, &Avatar::logoutResponse); getConnection()->send(l); } #pragma mark - void Avatar::drop(Entity* e, const WFMath::Point<3>& pos, const std::string& loc) { if(e->getLocation() != m_entity) { error() << "Can't drop an Entity which is not held by the character"; return; } Move moveOp; moveOp->setFrom(m_entityId); Anonymous what; what->setLoc(loc); Atlas::Message::Element apos(pos.toAtlas()); what->setPosAsList(apos.asList()); what->setId(e->getId()); moveOp->setArgs1(what); getConnection()->send(moveOp); } void Avatar::drop(Entity* e, const WFMath::Vector<3>& offset) { drop(e, m_entity->getPosition() + offset, m_entity->getLocation()->getId()); } void Avatar::take(Entity* e) { Move moveOp; moveOp->setFrom(m_entityId); Anonymous what; what->setLoc(m_entityId); std::vector p(3, 0.0); what->setPos(p); // cyphesis is rejecting move ops with no pos set what->setId(e->getId()); moveOp->setArgs1(what); getConnection()->send(moveOp); } void Avatar::touch(Entity* e) { Touch touchOp; touchOp->setFrom(m_entityId); Anonymous what; what->setId(e->getId()); touchOp->setArgs1(what); getConnection()->send(touchOp); } void Avatar::say(const std::string& msg) { Talk t; Anonymous what; what->setAttr("say", msg); t->setArgs1(what); t->setFrom(m_entityId); getConnection()->send(t); } void Avatar::emote(const std::string &em) { Imaginary im; Anonymous emote; emote->setId("emote"); emote->setAttr("description", em); im->setArgs1(emote); im->setFrom(m_entityId); im->setSerialno(getNewSerialno()); getConnection()->send(im); } void Avatar::moveToPoint(const WFMath::Point<3>& pos) { Anonymous what; what->setLoc(m_entity->getLocation()->getId()); what->setId(m_entityId); what->setAttr("pos", pos.toAtlas()); Move moveOp; moveOp->setFrom(m_entityId); moveOp->setArgs1(what); getConnection()->send(moveOp); } void Avatar::moveInDirection(const WFMath::Vector<3>& vel) { const double MIN_VELOCITY = 1e-3; Anonymous arg; //arg->setAttr("location", m_entity->getLocation()->getId()); arg->setId(m_entityId); arg->setAttr("velocity", vel.toAtlas()); WFMath::CoordType sqr_mag = vel.sqrMag(); if(sqr_mag > MIN_VELOCITY) { // don't set orientation for zero velocity WFMath::Quaternion q; WFMath::CoordType z_squared = vel.z() * vel.z(); WFMath::CoordType plane_sqr_mag = sqr_mag - z_squared; if(plane_sqr_mag < WFMATH_EPSILON * z_squared) { // it's on the z axis q.rotation(1, vel[2] > 0 ? -WFMath::Pi/2 : WFMath::Pi/2); } else { // rotate in the plane first q.rotation(2, atan2(vel[1], vel[0])); // then get the angle away from the plane q = WFMath::Quaternion(1, -asin(vel[2] / sqrt(plane_sqr_mag))) * q; } arg->setAttr("orientation", q.toAtlas()); } Move moveOp; moveOp->setFrom(m_entityId); moveOp->setArgs1(arg); getConnection()->send(moveOp); } void Avatar::moveInDirection(const WFMath::Vector<3>& vel, const WFMath::Quaternion& orient) { Anonymous arg; // arg->setAttr("location", m_entity->getLocation()->getId()); arg->setAttr("velocity", vel.toAtlas()); arg->setAttr("orientation", orient.toAtlas()); arg->setId(m_entityId); Move moveOp; moveOp->setFrom(m_entityId); moveOp->setArgs1(arg); getConnection()->send(moveOp); } void Avatar::place(Entity* e, Entity* container, const WFMath::Point<3>& pos) { Anonymous what; what->setLoc(container->getId()); what->setAttr("pos", pos.toAtlas()); // what->setVelocityAsList( .... zero ... ); what->setId(e->getId()); Move moveOp; moveOp->setFrom(m_entityId); moveOp->setArgs1(what); getConnection()->send(moveOp); } void Avatar::wield(Entity * entity) { if(entity->getLocation() != m_entity) { error() << "Can't wield an Entity which is not located in the avatar."; return; } Anonymous arguments; arguments->setId(entity->getId()); Wield wield; wield->setFrom(m_entityId); wield->setArgs1(arguments); getConnection()->send(wield); } void Avatar::useOn(Entity * entity, const WFMath::Point< 3 > & position, const std::string& opType) { Anonymous arguments; arguments->setId(entity->getId()); arguments->setObjtype("obj"); if (position.isValid()) arguments->setAttr("pos", position.toAtlas()); Use use; use->setFrom(m_entityId); if (opType.empty()) { use->setArgs1(arguments); } else { RootOperation op; StringList prs; prs.push_back(opType); op->setParents(prs); op->setArgs1(arguments); op->setFrom(m_entityId); use->setArgs1(op); } getConnection()->send(use); } void Avatar::attack(Entity* entity) { assert(entity); Attack attackOp; attackOp->setFrom(m_entityId); Anonymous what; what->setId(entity->getId()); attackOp->setArgs1(what); getConnection()->send(attackOp); } void Avatar::useStop() { Use use; use->setFrom(m_entityId); getConnection()->send(use); } #pragma mark - void Avatar::onEntityAppear(Entity* ent) { if (ent->getId() == m_entityId) { assert(m_entity == NULL); m_entity = ent; ent->ChildAdded.connect(sigc::mem_fun(this, &Avatar::onCharacterChildAdded)); ent->ChildRemoved.connect(sigc::mem_fun(this, &Avatar::onCharacterChildRemoved)); ent->observe("right_hand_wield", sigc::mem_fun(this, &Avatar::onCharacterWield)); GotCharacterEntity.emit(ent); m_entityAppearanceCon.disconnect(); // stop listenting to View::Appearance } } void Avatar::onCharacterChildAdded(Entity* child) { InvAdded.emit(child); } void Avatar::onCharacterChildRemoved(Entity* child) { InvRemoved.emit(child); } void Avatar::onCharacterWield(const std::string& s, const Atlas::Message::Element& val) { if (s != "right_hand_wield") { warning() << "got wield for strange slot"; return; } if (!val.isString()) { warning() << "got malformed wield value"; return; } m_wielded = EntityRef(m_view, val.asString()); } Connection* Avatar::getConnection() const { return m_account->getConnection(); } double Avatar::getWorldTime() { WFMath::TimeDiff deltaT = TimeStamp::now() - m_stampAtLastOp; return m_lastOpTime + (deltaT.milliseconds() / 1000.0); } void Avatar::updateWorldTime(double seconds) { m_stampAtLastOp = TimeStamp::now(); m_lastOpTime = seconds; } void Avatar::logoutResponse(const RootOperation& op) { if (!op->instanceOf(INFO_NO)) warning() << "received an avatar logout response that is not an INFO"; const std::vector& args(op->getArgs()); if (args.empty() || (args.front()->getClassNo() != LOGOUT_NO)) { warning() << "argument of avatar logout INFO is not a logout op"; return; } RootOperation logout = smart_dynamic_cast(args.front()); const std::vector& args2(logout->getArgs()); assert(!args2.empty()); std::string charId = args2.front()->getId(); debug() << "got logout for character " << charId; assert(charId == m_entityId); m_account->AvatarDeactivated.emit(this); deleteLater(this); } } // of namespace Eris