//======================================================================== // // CreatureController.cpp // // copyright 2001 Sony Online Entertainment // //======================================================================== #include "serverGame/FirstServerGame.h" #include "serverGame/CreatureController.h" #include "SwgGameServer/CombatEngine.h" #include "SwgGameServer/ConfigCombatEngine.h" #include "serverGame/Chat.h" #include "serverGame/ConfigServerGame.h" #include "serverGame/ContainerInterface.h" #include "serverGame/CreatureObject.h" #include "serverGame/GameServer.h" #include "serverGame/GroupObject.h" #include "serverGame/HarvesterInstallationObject.h" #include "serverGame/InstallationObject.h" #include "serverGame/ObjectTracker.h" #include "serverGame/PlayerCreatureController.h" #include "serverGame/PlayerObject.h" #include "serverGame/ServerSecureTrade.h" #include "serverGame/ServerSecureTradeManager.h" #include "serverGame/ServerUniverse.h" #include "serverGame/ServerWeaponObjectTemplate.h" #include "serverGame/ServerWorld.h" #include "serverGame/ShipObject.h" #include "serverGame/WeaponObject.h" #include "serverNetworkMessages/MessageQueueAlterAttribute.h" #include "serverNetworkMessages/MessageQueueCommandQueueEnqueueFwd.h" #include "serverNetworkMessages/MessageQueueSetState.h" #include "serverScript/GameScriptObject.h" #include "serverScript/ScriptParameters.h" #include "serverUtility/ServerClock.h" #include "sharedCollision/CollisionProperty.h" #include "sharedCollision/Footprint.h" #include "sharedDebug/Profiler.h" #include "sharedFoundation/GameControllerMessage.h" #include "sharedLog/Log.h" #include "sharedGame/CommandTable.h" #include "sharedUtility/Location.h" #include "sharedGame/GameObjectTypes.h" #include "sharedGame/ProsePackage.h" #include "sharedGame/Waypoint.h" #include "sharedNetworkMessages/GenericValueTypeMessage.h" #include "sharedNetworkMessages/IncubatorCommitMessage.h" #include "sharedNetworkMessages/MessageQueueCombatCommand.h" #include "sharedNetworkMessages/MessageQueueCommandQueueEnqueue.h" #include "sharedNetworkMessages/MessageQueueCommandQueueRemove.h" #include "sharedNetworkMessages/MessageQueueCyberneticsChangeRequest.h" #include "sharedNetworkMessages/MessageQueueDataTransform.h" #include "sharedNetworkMessages/MessageQueueDataTransformWithParent.h" #include "sharedNetworkMessages/MessageQueueGeneric.h" #include "sharedNetworkMessages/MessageQueueGenericIntResponse.h" #include "sharedNetworkMessages/MessageQueueGenericResponse.h" #include "sharedNetworkMessages/MessageQueueGenericString.h" #include "sharedNetworkMessages/MessageQueueGenericValueType.h" #include "sharedNetworkMessages/MessageQueueHarvesterResourceData.h" #include "sharedNetworkMessages/MessageQueueNetworkId.h" #include "sharedNetworkMessages/MessageQueueNetworkIdPair.h" #include "sharedNetworkMessages/MessageQueuePosture.h" #include "sharedNetworkMessages/MessageQueuePushCreature.h" #include "sharedNetworkMessages/MessageQueueResourceEmptyHopper.h" #include "sharedNetworkMessages/MessageQueueSecureTrade.h" #include "sharedNetworkMessages/MessageQueueSitOnObject.h" #include "sharedNetworkMessages/MessageQueueSlowDownEffect.h" #include "sharedNetworkMessages/ObjectChannelMessages.h" #include "sharedNetworkMessages/UpdateTransformMessage.h" #include "sharedNetworkMessages/UpdateTransformWithParentMessage.h" #include "sharedObject/AlterResult.h" #include "sharedObject/CellProperty.h" #include "sharedObject/MovementTable.h" #include "sharedObject/NetworkIdManager.h" #include "sharedObject/ObjectTemplateList.h" #include "sharedSkillSystem/SkillManager.h" #include "sharedTerrain/TerrainObject.h" #include "sharedTerrain/WaterTypeManager.h" #include "swgSharedNetworkMessages/MessageQueueCombatAction.h" #include "Unicode.h" #include "UnicodeUtils.h" //----------------------------------------------------------------------- namespace CreatureControllerNamespace { template ObjectType & getOwner(Controller * controller) { NOT_NULL(controller); NOT_NULL(controller->getOwner()); ObjectType * owner = static_cast(controller->getOwner()); return *owner; } } //----------------------------------------------------------------------- CreatureController::CreatureController(CreatureObject * newOwner) : TangibleController(newOwner), m_secureTrade(0), m_secureTradeInitiator(0) { } //----------------------------------------------------------------------- CreatureController::~CreatureController() { if (getHibernate()) ObjectTracker::removeHibernatingAI(); if (m_secureTrade) m_secureTrade->cancelTrade(*getCreature()); } //----------------------------------------------------------------------- void CreatureController::handleMessage (const int message, const float value, const MessageQueue::Data* const data, const uint32 flags) { CreatureObject * const owner = static_cast(getOwner()); DEBUG_FATAL(!owner, ("Owner is NULL in CreatureController::handleMessage\n")); switch(message) { case CM_netUpdateTransform: { // if the auth server sent this to us, forward it to clients const MessageQueueDataTransform * const msg = NON_NULL (dynamic_cast(data)); owner->setLookAtYaw(msg->getLookAtYaw(), msg->getUseLookAtYaw()); if (flags&GameControllerMessageFlags::SOURCE_REMOTE_SERVER) { // If we're not contained by what we are attached to, then transform // updates are not relevant to clients because our position is // dictated purely by our containing object. if (owner->getAttachedTo() == ContainerInterface::getContainedByObject(*owner)) { UpdateTransformMessage utm(owner->getNetworkId(), msg->getSequenceNumber(), msg->getTransform(), static_cast(msg->getSpeed()), msg->getLookAtYaw(), msg->getUseLookAtYaw()); owner->sendToClientsInUpdateRange(utm, flags & GameControllerMessageFlags::RELIABLE, false); } } TangibleController::handleMessage(message, value, data, flags); } break; case CM_netUpdateTransformWithParent: { // if the auth server sent this to us, forward it to clients const MessageQueueDataTransformWithParent * const msg = NON_NULL (dynamic_cast(data)); owner->setLookAtYaw(msg->getLookAtYaw(), msg->getUseLookAtYaw()); if (flags&GameControllerMessageFlags::SOURCE_REMOTE_SERVER) { // If we're not contained by what we are attached to, then transform // updates are not relevant to clients because our position is // dictated purely by our containing object. if (owner->getAttachedTo() == ContainerInterface::getContainedByObject(*owner)) { UpdateTransformWithParentMessage utm(owner->getNetworkId(), msg->getSequenceNumber(), msg->getParent(), msg->getTransform(), static_cast(msg->getSpeed()), msg->getLookAtYaw(), msg->getUseLookAtYaw()); owner->sendToClientsInUpdateRange(utm, flags & GameControllerMessageFlags::RELIABLE, false); } } TangibleController::handleMessage(message, value, data, flags); } break; case CM_clientResourceHarvesterActivate: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); InstallationObject * const harvester = dynamic_cast(ServerWorld::findObjectByNetworkId (msg->getNetworkId ())); UNREF (harvester); if (harvester && harvester->isOnAdminList(*owner)) harvester->activate (owner->getNetworkId()); } break; case CM_clientResourceHarvesterDeactivate: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); InstallationObject * const harvester = dynamic_cast(ServerWorld::findObjectByNetworkId (msg->getNetworkId ())); if (harvester && harvester->isOnAdminList(*owner)) harvester->deactivate (); } break; case CM_clientResourceHarvesterListen: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); HarvesterInstallationObject * const harvester = dynamic_cast(ServerWorld::findObjectByNetworkId (msg->getNetworkId ())); if (harvester && owner) harvester->addSynchronizedUiClient (*owner); } break; case CM_clientResourceHarvesterStopListening: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); HarvesterInstallationObject * const harvester = dynamic_cast(ServerWorld::findObjectByNetworkId (msg->getNetworkId ())); if (harvester && owner) harvester->removeSynchronizedUiClient (owner->getNetworkId ()); } break; case CM_clientResourceHarvesterResourceSelect: { const MessageQueueNetworkIdPair * const msg = NON_NULL (dynamic_cast(data)); HarvesterInstallationObject * const harvester = dynamic_cast(ServerWorld::findObjectByNetworkId (msg->getFirstNetworkId ())); harvester->selectResource (msg->getSecondNetworkId (), owner->getNetworkId()); } break; case CM_clientResourceHarvesterGetResourceData: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); typedef stdvector::fwd DataVector; DataVector dv; HarvesterInstallationObject * const harvester = dynamic_cast(ServerWorld::findObjectByNetworkId (msg->getNetworkId ())); ServerObject * const player = owner; if (harvester && player) { harvester->getResourceData (dv); if (!dv.empty ()) { MessageQueueHarvesterResourceData * const newData = new MessageQueueHarvesterResourceData (msg->getNetworkId (), dv); appendMessage(static_cast(CM_clientResourceHarvesterResourceData), 0.0f, newData, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); } } } break; case CM_clientResourceHarvesterEmptyHopper: { const MessageQueueResourceEmptyHopper * const msg = NON_NULL (dynamic_cast(data)); HarvesterInstallationObject * const harvester = dynamic_cast(ServerWorld::findObjectByNetworkId (msg->getHarvesterId ())); if (harvester && owner && harvester->isOnHopperList(*owner)) harvester->emptyHopper (msg->getPlayerId(),msg->getResourceId(), msg->getAmount(),msg->getDiscard(),msg->getSequenceId()); } break; case CM_getTokenForObject: { WARNING_STRICT_FATAL(true, ("Received CM_getTokenForObject controller message. This message is depracated")); } break; case CM_getWaypointForObject: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); if(msg) { if(owner) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { const ServerObject * target = ServerWorld::findObjectByNetworkId(msg->getNetworkId()); if(target) { const Object * topMost = ContainerInterface::getFirstParentInWorld(*target); if(topMost) { const Vector pos = topMost->getPosition_w(); IGNORE_RETURN(player->createWaypoint(Location(pos, NetworkId::cms_invalid, Location::getCrcBySceneName(ServerWorld::getSceneId())), true)); } } } } } } break; case CM_secureTrade: { if (owner->isAuthoritative()) { handleSecureTradeMessage(dynamic_cast(data)); } // @todo else //resend to auth } break; case CM_clientLookAtTarget: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); owner->setLookAtTarget (msg->getNetworkId ()); } break; case CM_clientIntendedTarget: { const MessageQueueNetworkId * const msg = NON_NULL (dynamic_cast(data)); owner->setIntendedTarget (msg->getNetworkId ()); } break; case CM_clientMoodChange: if (value < 0.0f || value > 255.0f) WARNING (true, ("Out of range mood: %f", value)); else owner->setMood (static_cast(value)); break; case CM_setState: { if (!(flags&GameControllerMessageFlags::SOURCE_REMOTE_CLIENT)) { MessageQueueSetState const *msg = safe_cast(data); owner->setState(static_cast(msg->getState()), msg->getValue()); } } break; case CM_setAttribute: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(owner) { const std::pair & attributePair = msg->getValue(); if(msg) { owner->setAttribute(attributePair.first, attributePair.second); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setAttribute message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } } break; case CM_setMaxAttribute: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); // set the object value and send a message to all it's proxies if(msg) { owner->setMaxAttribute(msg->getValue().first, msg->getValue().second); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setMaxAttribute message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setMentalState: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); // set the object value and send a message to all it's proxies if(msg) { owner->setMentalState(msg->getValue().first, msg->getValue().second); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setMentalState message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setMentalStateToward: { const MessageQueueGenericValueType > > * const msg = safe_cast > > *>(data); if(msg) { owner->setMentalStateToward(msg->getValue().first, msg->getValue().second.first, msg->getValue().second.second); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setMentalStateToward message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setCover: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setCover(msg->getValue()); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setCover message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setMentalStateTowardClampBehavior: { const MessageQueueGenericValueType > > > * const msg = safe_cast > > > *>(data); if(msg) { owner->setMentalStateTowardClampBehavior( msg->getValue().first, msg->getValue().second.first, msg->getValue().second.second.first, msg->getValue().second.second.second); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setMentalStateTowardClampBehavior message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setMaxMentalState: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { owner->setMaxMentalState(msg->getValue().first, msg->getValue().second); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setMaxMentalState message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setMentalStateDecay: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { owner->setMentalStateDecay(msg->getValue().first, msg->getValue().second); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setMentalStateDecay message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setPosture: { const MessageQueuePosture * const msg = safe_cast(data); if(msg) { owner->setPosture(msg->getPosture(), msg->isClientImmediate()); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setPosture message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setLocomotion: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setLocomotion(msg->getValue()); } DEBUG_WARNING(! msg, ("CreatureController (%s:%s) received a CM_setLocomotion message but could not retrieve data from the message supplied", owner->getObjectTemplateName(), owner->getNetworkId().getValueString().c_str())); } break; case CM_setGroupInviter: { const MessageQueueGenericValueType > > * const msg = safe_cast > > *>(data); if (msg) { owner->setGroupInviter(msg->getValue().second.first, msg->getValue().first, msg->getValue().second.second); } } break; case CM_setPerformanceType: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if (msg) { owner->setPerformanceType(msg->getValue()); } } break; case CM_setPerformanceStartTime: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if (msg) { owner->setPerformanceStartTime(msg->getValue()); } } break; case CM_setPerformanceListenTarget: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if (msg) { owner->setPerformanceListenTarget(msg->getValue()); } } break; case CM_setPerformanceWatchTarget: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if (msg) { owner->setPerformanceWatchTarget(msg->getValue()); } } break; case CM_setModValue: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { owner->setModValue(msg->getValue().first, msg->getValue().second); } } break; case CM_grantCommand: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->grantCommand(msg->getValue(), false); } } break; case CM_grantExperiencePoints: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { owner->grantExperiencePoints(msg->getValue().first, msg->getValue().second); } } break; case CM_incrementKillMeter: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->incrementKillMeter(msg->getValue()); } } break; case CM_grantSkill: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { const SkillObject * newSkill = SkillManager::getInstance().getSkill(msg->getValue()); if(newSkill) { owner->grantSkill(*newSkill); } } } break; case CM_revokeCommand: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->revokeCommand(msg->getValue(), false); } } break; case CM_revokeSkill: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { const SkillObject * oldSkill = SkillManager::getInstance().getSkill(msg->getValue()); if(oldSkill) { LOG("CustomerService", ("Skill: Removing skill %s from character %s via controller message.", msg->getValue().c_str(), owner->getNetworkId().getValueString().c_str())); owner->revokeSkill(*oldSkill); } } } break; case CM_alterAttribute: { const MessageQueueAlterAttribute * const msg = safe_cast(data); if(msg) { owner->alterAttribute(msg->getAttrib(), msg->getDelta(), msg->getCheckIncapacitation(), msg->getSource() ); } } break; case CM_addAttributeModifier: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->addAttributeModifier(msg->getValue()); } } break; case CM_removeAttributeModifiers: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->removeAttributeModifiers(msg->getValue()); } } break; case CM_removeAllAttributeModifiers: { owner->removeAllAttributeModifiers(); } break; case CM_removeAllAttributeAndSkillmodModifiers: { owner->removeAllAttributeAndSkillmodMods(); } break; case CM_setCurrentWeapon: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { WeaponObject * weapon = safe_cast(NetworkIdManager::getObjectById(msg->getValue())); if(weapon) owner->setCurrentWeapon(*weapon); } } break; case CM_setGroup: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { GroupObject * group = safe_cast(NetworkIdManager::getObjectById(msg->getValue().second)); if (group) { owner->setGroup(group, msg->getValue().first); } else if (!msg->getValue().second.isValid()) { if (owner->getGroup()) owner->getGroup()->onGroupMemberRemoved(owner->getNetworkId(), msg->getValue().first); } } } break; case CM_setIncapacitated: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if (msg != NULL) owner->setIncapacitated(msg->getValue().first, msg->getValue().second); } break; case CM_setSayMode: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setSayMode(msg->getValue()); } } break; case CM_setAnimationMood: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setAnimationMood(msg->getValue()); } } break; case CM_setScaleFactor: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setScaleFactor(msg->getValue()); } } break; case CM_setShockWounds: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setShockWounds(msg->getValue()); } } break; case CM_setLookAtTarget: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setLookAtTarget(msg->getValue()); } } break; case CM_setIntendedTarget: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setIntendedTarget(msg->getValue()); } } break; case CM_setMovementStationary: { owner->setMovementStationary(); } break; case CM_setMovementWalk: { owner->setMovementWalk(); } break; case CM_setMovementRun: { owner->setMovementRun(); } break; case CM_setSlopeModAngle: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setSlopeModAngle(msg->getValue()); } } break; case CM_setSlopeModPercent: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setSlopeModPercent(msg->getValue()); } } break; case CM_setWaterModPercent: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setWaterModPercent(msg->getValue()); } } break; case CM_setMovementScale: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setMovementScale(msg->getValue()); } } break; case CM_setMovementPercent: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setMovementPercent(msg->getValue()); } } break; case CM_setTurnPercent: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setTurnPercent(msg->getValue()); } } break; case CM_setAccelScale: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setAccelScale(msg->getValue()); } } break; case CM_setAccelPercent: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { owner->setAccelPercent(msg->getValue()); } } break; case CM_sitOnObject: { const MessageQueueSitOnObject * const msg = safe_cast(data); if(msg) { owner->sitOnObject(msg->getChairCellId(), msg->getChairPosition_p()); } } break; case CM_setMasterId: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if (msg) { owner->setMasterId(msg->getValue()); } } break; case CM_setHouse: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if (msg) { owner->setHouse(CachedNetworkId(msg->getValue())); } } break; case CM_setDifficulty: case CM_setLevel: { MessageQueueGenericValueType const *msg = safe_cast const *>(data); if (msg) owner->setLevel(static_cast(msg->getValue())); } break; case CM_recalculateLevel: { MessageQueueGenericValueType const *msg = safe_cast const *>(data); if (msg) owner->recalculateLevel(); } break; case CM_creatureSetBaseWalkSpeed: owner->setBaseWalkSpeed(value); break; case CM_creatureSetBaseRunSpeed: owner->setBaseRunSpeed(value); break; case CM_emergencyDismountForRider: owner->emergencyDismountForRider(); break; case CM_detachRiderForMount: { typedef MessageQueueGenericValueType Message; Message const * const msg = safe_cast(data); if (msg != 0) { owner->detachRider(msg->getValue()); } break; } case CM_detachAllRidersForMount: owner->detachAllRiders(); break; case CM_setAppearanceFromObjectTemplate: { MessageQueueGenericValueType const *const msg = dynamic_cast const *>(data); if (owner && msg) owner->setAlternateAppearance(msg->getValue()); else WARNING(true, ("CreatureController: received CM_setAppearanceFromObjectTemplate but owner or message was NULL.")); } break; case CM_makeDead: { const MessageQueueGenericValueType > * msg = dynamic_cast > *>(data); if (msg) { owner->makeDead(msg->getValue().first, msg->getValue().second); } } break; case CM_pushCreature: { const MessageQueuePushCreature * const msg = safe_cast(data); if (msg) { ServerObject * defender = safe_cast(NetworkIdManager::getObjectById(msg->getDefender())); if (defender != NULL) { if (defender->asCreatureObject() != NULL) { defender->asCreatureObject()->pushedMe(msg->getAttacker(), msg->getAttackerPos(), msg->getDefenderPos(), msg->getDistance()); } else { WARNING(true, ("Received MessageQueuePushCreature for non-creature defender %s", msg->getDefender().getValueString().c_str())); } } } } break; case CM_slowDownEffect: { const MessageQueueSlowDownEffect * const msg = safe_cast(data); if (msg) { ServerObject * target = safe_cast(NetworkIdManager::getObjectById(msg->getTarget())); if (target != NULL && target->asTangibleObject() != NULL) { if (owner->isAuthoritative()) owner->addSlowDownEffect(*(target->asTangibleObject()), msg->getConeLength(), msg->getConeAngle(), msg->getSlopeAngle(), msg->getExpireTime()); else owner->addSlowDownEffectProxy(*(target->asTangibleObject()), msg->getConeLength(), msg->getConeAngle(), msg->getSlopeAngle(), msg->getExpireTime()); } else { WARNING(true, ("Received slow down effect messge for creature %s " "with unknown target %s", owner->getNetworkId().getValueString().c_str(), msg->getTarget().getValueString().c_str())); } } } break; case CM_removeSlowDownEffect: { if (owner->isAuthoritative()) owner->removeSlowDownEffect(); else { WARNING(true, ("CM_removeSlowDownEffect message recieved by proxy object %s", owner->getNetworkId().getValueString().c_str())); } } break; case CM_removeSlowDownEffectProxy: { if (!owner->isAuthoritative()) owner->removeSlowDownEffectProxy(); else { WARNING(true, ("CM_removeSlowDownEffectProxy message recieved by authoritative object %s", owner->getNetworkId().getValueString().c_str())); } } break; case CM_groupLotteryWindowCloseResults: { typedef std::pair > Payload; MessageQueueGenericValueType const * const msg = safe_cast const *>(data); if (msg != 0) { Payload const & incomingPayload = msg->getValue(); typedef std::vector Ids; NetworkId const & player = incomingPayload.first; Ids const & selectedItems = incomingPayload.second; GameScriptObject * const scriptObject = owner->getScriptObject(); if (scriptObject != 0) { ScriptParams params; params.addParam(player); params.addParam(selectedItems); IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_LOOT_LOTTERY_SELECTED, params)); } } } break; case CM_cyberneticsChangeRequestToNPC: { MessageQueueCyberneticsChangeRequest const * const msg = safe_cast(data); NOT_NULL(msg); if (msg != NULL) { NetworkId const & playerId = msg->getTarget(); GameScriptObject * const scriptObject = owner->getScriptObject(); if (scriptObject) { ScriptParams params; params.addParam(playerId); params.addParam(static_cast(msg->getChangeType())); params.addParam(msg->getCyberneticPiece()); IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_CYBERNETIC_CHANGE_REQUEST, params)); } } } break; case CM_setCurrentQuest: { MessageQueueGenericValueType const * const msg = safe_cast const *>(data); if (msg != NULL) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if (player != NULL) { player->setCurrentQuest(msg->getValue()); } else { DEBUG_WARNING(true, ("Non-player creature %s sent CM_setCurrentQuest message (%u)", owner->getNetworkId().getValueString().c_str(), msg->getValue())); } } } break; case CM_setRegenRate: { MessageQueueGenericValueType > const * const msg = safe_cast > const *>(data); if (msg != NULL) { owner->setRegenRate(static_cast(msg->getValue().first), msg->getValue().second); } } break; case CM_modifyCurrentGcwPoints: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyCurrentGcwPoints(msg->getValue().first, (msg->getValue().second != 0)); } } } break; case CM_modifyCurrentGcwRating: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyCurrentGcwRating(msg->getValue().first, (msg->getValue().second != 0)); } } } break; case CM_modifyCurrentPvpKills: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyCurrentPvpKills(msg->getValue().first, (msg->getValue().second != 0)); } } } break; case CM_modifyLifetimeGcwPoints: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyLifetimeGcwPoints(msg->getValue()); } } } break; case CM_modifyMaxGcwImperialRating: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyMaxGcwImperialRating(msg->getValue()); } } } break; case CM_modifyMaxGcwRebelRating: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyMaxGcwRebelRating(msg->getValue()); } } } break; case CM_modifyLifetimePvpKills: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyLifetimePvpKills(msg->getValue()); } } } break; case CM_modifyNextGcwRatingCalcTime: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyNextGcwRatingCalcTime(msg->getValue()); } } } break; case CM_customizeFinished: { typedef std::pair Payload; MessageQueueGenericValueType const * const msg = safe_cast const *>(data); if (msg != 0) { Payload const & incomingPayload = msg->getValue(); NetworkId const & object = incomingPayload.first; std::string const & msgValue = incomingPayload.second; GameScriptObject * const scriptObject = owner->getScriptObject(); if (scriptObject != 0) { ScriptParams params; params.addParam(object); params.addParam(msgValue.c_str()); IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_ON_CUSTOMIZE_FINISHED, params)); } } } break; case CM_clearSessionActivity: { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->clearSessionActivity(); } } break; case CM_addSessionActivity: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->addSessionActivity(static_cast(msg->getValue())); } } } break; case CM_modifyHologramType: { MessageQueueGenericValueType const *msg = safe_cast const *>(data); if (msg) owner->setHologramType(msg->getValue()); } break; case CM_modifyVisibleOnMapAndRadar: { MessageQueueGenericValueType const *msg = safe_cast const *>(data); if (msg) owner->setVisibleOnMapAndRadar(msg->getValue()); } break; case CM_setCoverVisibility: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if (msg) { owner->setCoverVisibility(msg->getValue()); } } break; case CM_incubatorCancel: { IncubatorCommitMessage const * const msg = safe_cast(data); if (msg) { ServerObject * incubatorSo = ServerWorld::findObjectByNetworkId(msg->getTerminalId()); if (incubatorSo) { TangibleObject * incubatorTo = incubatorSo->asTangibleObject(); if (incubatorTo) incubatorTo->handleIncubatorCancel(*owner); } } } break; case CM_incubatorCommit: { IncubatorCommitMessage const * const msg = safe_cast(data); if (msg) { ServerObject * incubatorSo = ServerWorld::findObjectByNetworkId(msg->getTerminalId()); if (incubatorSo) { TangibleObject * incubatorTo = incubatorSo->asTangibleObject(); if (incubatorTo) incubatorTo->handleIncubatorCommit(*owner, *msg); } } } break; case CM_modifyCollectionSlotValue: { const MessageQueueGenericValueType > * const msg = safe_cast > *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->modifyCollectionSlotValue(msg->getValue().first, msg->getValue().second); } } } break; case CM_adjustLotCount: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->adjustLotCount(msg->getValue()); } } } break; case CM_squelch: { const MessageQueueGenericValueType > > * const msg = safe_cast > > *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->squelch(msg->getValue().second.first, msg->getValue().first, msg->getValue().second.second); } } } break; case CM_unsquelch: { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->unsquelch(); } } break; case CM_setPriviledgedTitle: { const MessageQueueGenericValueType * const msg = safe_cast *>(data); if(msg) { PlayerObject * player = PlayerCreatureController::getPlayerObject(owner); if(player) { player->setPriviledgedTitle(static_cast(msg->getValue())); } } } break; case CM_addBuff: { const MessageQueueGenericValueType > > > > * const msg = safe_cast > > > > *>(data); if(msg) { owner->addBuff (static_cast(msg->getValue ().first), msg->getValue ().second.first, msg->getValue ().second.second.first, msg->getValue ().second.second.second.first, msg->getValue ().second.second.second.second); } } break; case CM_removeBuff: { const MessageQueueGenericValueType * const msg = safe_cast * >(data); if(msg) { owner->removeBuff (static_cast(msg->getValue ())); } } break; case CM_ratingFinished: { const MessageQueueGenericValueType * const msg = safe_cast * >(data); if(msg) { if(owner->getScriptObject()) { ScriptParams params; params.addParam(msg->getValue()); IGNORE_RETURN(owner->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_RATING_FINISHED, params)); } } } break; case CM_abandonPlayerQuest: { const MessageQueueGenericValueType * const msg = safe_cast * >(data); if(msg) { if(owner->getScriptObject()) { ScriptParams params; params.addParam(msg->getValue()); IGNORE_RETURN(owner->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_ABANDON_PLAYER_QUEST, params)); } } } break; default: TangibleController::handleMessage(message, value, data, flags); break; } } //----------------------------------------------------------------------- float CreatureController::realAlter(float time) { PROFILER_AUTO_BLOCK_DEFINE("CreatureController::realAlter"); float alterResult = TangibleController::realAlter(time); CreatureObject * const owner = NON_NULL(getCreature()); if(getHibernate()) return alterResult; if (owner->isAuthoritative()) owner->decayAttributes(time); if (owner->isInWorld()) { bool isBurning = false; float lavaResistance = 0.0f; if (owner->isAuthoritative()) { //owner->decayMentalStates(time); owner->reportMonitoredCreatures(time); //-- Handle swimming state. bool const currentSwimState = owner->getState(States::Swimming); bool newSwimState = false; float waterHeight = 0.0f; calculateWaterState(newSwimState,isBurning,lavaResistance,waterHeight); bool const isVehicle = GameObjectTypes::isTypeOf (owner->getGameObjectType (), static_cast(SharedObjectTemplate::GOT_vehicle)); if(!isVehicle) // make everything but vehicles walk on lava { const Vector & position = owner->getPosition_w (); Footprint *const footprint = owner->getFootprint(); if(footprint) { if(isBurning) { footprint->setSwimHeight(owner->getSwimHeight() * 0.2f); owner->move_p(Vector::unitY * (waterHeight - position.y)); } else { footprint->setSwimHeight(owner->getSwimHeight()); } } } if (currentSwimState && !newSwimState) { // We've just detected that the owner stopped swimming. onExitSwimming(); } else if (!currentSwimState && newSwimState) { // We've just detected that the owner started swimming. onEnterSwimming(); } setObjectStopWalkRun(); } CollisionProperty *const collisionProperty = owner->getCollisionProperty(); if (owner->getState(States::RidingMount)) { // Tell the rider's CollisionProperty to update its extent. Since // the rider is yanked out of the CollisionWorld, the // CollisionProperty doesn't get updated properly. Failure to // update the rider's CollisionProperty extent causes line of sight // to fail (line of sight ends up using the value present in CollisionProperty // at the time of mounting). if (collisionProperty) collisionProperty->updateExtents(); } const bool isPlayerControlled = (collisionProperty && collisionProperty->isPlayerControlled()); // lava damage if(WaterTypeManager::getCausesDamage(TGWT_lava) && isBurning && (isPlayerControlled || owner->isBeast()) ) { const unsigned long serverTime = ServerClock::getInstance().getGameTimeSeconds(); const unsigned long lastBurnTime = owner->getLastWaterDamageTime(); const unsigned long waterDamageInterval = WaterTypeManager::getDamageInterval(TGWT_lava); if(serverTime - lastBurnTime > (waterDamageInterval*3)) // skip the first lava damage frame { owner->setLastWaterDamageTime(serverTime - waterDamageInterval); //DEBUG_WARNING(true,("LAVA DAMAGE SLUSH TIME- serverTime=%ul, lastBurnTime=%ul, diff=%d",serverTime,lastBurnTime,serverTime-lastBurnTime)); } else if(serverTime - lastBurnTime > waterDamageInterval && !owner->isDead()) { owner->setLastWaterDamageTime(serverTime); const float percentWaterDamagePerInterval = WaterTypeManager::getDamagePerInterval(TGWT_lava)/100.0f; const float lavaResistanceModifier = 1.0f - lavaResistance/100.0f; const int damageValue = static_cast ( -( owner->getMaxAttribute(Attributes::Health) * percentWaterDamagePerInterval * lavaResistanceModifier ) ); StringId stringId = StringId("combat_effects", "environment_damage_lava"); owner->showFlyText(stringId,5.0f,255,0,0); if(WaterTypeManager::getDamageKills(TGWT_lava) && (owner->getAttribute(Attributes::Health) + damageValue) <= 0) { owner->makeDead(NetworkId::cms_invalid, NetworkId::cms_invalid); ScriptParams params; owner->getScriptObject()->trigAllScripts(Scripting::TRIG_ENVIRONMENTAL_DEATH,params); } else { CombatEngineData::DamageData damageData; struct AttribMod::AttribMod damage; damage.tag = 0; damage.attrib = Attributes::Health; damage.attack = 0; damage.sustain = 0; damage.decay = AttribMod::AMDS_pool; damage.flags = AttribMod::AMF_directDamage; damage.value = damageValue; damageData.damage.push_back(damage); owner->applyDamage(damageData); } } } } return alterResult; } // ---------------------------------------------------------------------- void CreatureController::conclude() { PROFILER_AUTO_BLOCK_DEFINE("CreatureController::conclude"); MessageQueue::Data* data; int message; real value; uint32 flags; NetworkId networkId; int const messageCount = getNumberOfMessages(); for(int i = 0; i < messageCount; ++i) { //-- Get the message. getMessage(i, &message, &value, &data, &flags); //@todo why does getMessage need a signed size? if(message == CM_combatAction) { //-- Check if it's a combat action message. If so, the message's end postures for the // combatants must be adjusted to reflect the server's idea of the post-alter end posture. // This information was not known at the time the message was constructed. MessageQueueCombatAction * combatMessage = safe_cast(data); if (combatMessage != NULL) { //-- Fix up end postures in messages. // @todo: change postures to locomotion // set the attacker's posture MessageQueueCombatAction::AttackerData & attackerData = const_cast( combatMessage->getAttacker()); const CreatureObject * attacker = dynamic_cast( NetworkIdManager::getObjectById(attackerData.id)); attackerData.endPosture = (attacker != NULL) ? attacker->getPosture() : static_cast(0); // set the defenders' posture const MessageQueueCombatAction::DefenderDataVector & defenderData = combatMessage->getDefenders(); for (MessageQueueCombatAction::DefenderDataVector::const_iterator iter(defenderData.begin()); iter != defenderData.end(); ++iter) { MessageQueueCombatAction::DefenderData & defenderData = const_cast(*iter); const CreatureObject * defender = dynamic_cast( NetworkIdManager::getObjectById(defenderData.id)); defenderData.endPosture = (defender != NULL) ? defender->getPosture() : static_cast(0); } } } } CreatureObject * const owner = static_cast(getOwner()); if(owner) { owner->checkNotifyRegions(); } //-- Chain up to parent controller. TangibleController::conclude(); } //-------------------------------------------------------------------- void CreatureController::setObjectStopWalkRun() { float vel = getCurrentVelocity().magnitude(); CreatureObject* owner = static_cast(getOwner()); float walkSpeed = owner->getWalkSpeed(); float runSpeed = owner->getRunSpeed(); if (vel == 0) owner->setMovementStationary(); else if (runSpeed == 0 || (vel < (walkSpeed + runSpeed) * 0.5f)) owner->setMovementWalk(); else owner->setMovementRun(); } //---------------------------------------------------------------------- void CreatureController::setOwner(Object *newOwner) { NOT_NULL(safe_cast(newOwner)); Controller::setOwner(newOwner); } // ---------------------------------------------------------------------- void CreatureController::setSecureTrade(ServerSecureTrade * t) { m_secureTrade = t; } //---------------------------------------------------------- ServerSecureTrade* CreatureController::getSecureTrade() const { return m_secureTrade; } //---------------------------------------------------------- void CreatureController::handleSecureTradeMessage(const MessageQueueSecureTrade * data) { if (!data) return; CreatureObject * owner = getCreature(); NOT_NULL(owner); switch (data->getTradeMessageId()) { case MessageQueueSecureTrade::TMI_RequestTrade: { if (data->getRecipient() == owner->getNetworkId()) { DEBUG_REPORT_LOG(true, ("Creature %s tried to trade with himself.", getOwner()->getNetworkId().getValueString().c_str())); return; } if (m_secureTrade) { DEBUG_REPORT_LOG(true, ("Creature %s is already trading\n", getOwner()->getNetworkId().getValueString().c_str())); return; } CreatureObject * recipient = dynamic_cast(ServerWorld::findObjectByNetworkId(data->getRecipient())); if (!recipient) { DEBUG_REPORT_LOG(true, ("Could not find recipient for secure trade message\n")); MessageQueueSecureTrade * m = new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_DeniedPlayerUnreachable, owner->getNetworkId(), data->getRecipient()); appendMessage(static_cast(CM_secureTrade), 0.0f, m, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); return; } if (owner->isIncapacitated() || owner->isDead()) { DEBUG_REPORT_LOG(true, ("Owner creature %s is incapacitated or dead.\n", getOwner()->getNetworkId().getValueString().c_str())); MessageQueueSecureTrade * m = new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_DeniedPlayerUnreachable, owner->getNetworkId(), data->getRecipient()); appendMessage(static_cast(CM_secureTrade), 0.0f, m, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); return; } else if (recipient->isIncapacitated() || recipient->isDead()) { DEBUG_REPORT_LOG(true, ("Recipient creature %s is incapacitated or dead.\n", getOwner()->getNetworkId().getValueString().c_str())); MessageQueueSecureTrade * m = new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_DeniedPlayerUnreachable, owner->getNetworkId(), data->getRecipient()); appendMessage(static_cast(CM_secureTrade), 0.0f, m, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); return; } if (! recipient->isAuthoritative()) { if (owner->isInWorldCell()) { // transfer player to authoritative server owner->transferAuthority(recipient->getAuthServerProcessId(), true, false, true); owner->sendControllerMessageToAuthServer(CM_secureTrade, new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_RequestTrade, owner->getNetworkId(), data->getRecipient())); } else if (recipient->isInWorldCell()) { recipient->sendControllerMessageToAuthServer(CM_secureTrade, new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_RequestTradeReversed, owner->getNetworkId(), data->getRecipient())); } else { DEBUG_REPORT_LOG(true, ("Player %s tried to trade with player " "%s, but both were in interiors that are on different " "servers. Cell/server= (%s/%lu), (%s/%lu)", owner->getNetworkId().getValueString().c_str(), recipient->getNetworkId().getValueString().c_str(), ContainerInterface::getTopmostContainer(*owner)->getNetworkId().getValueString().c_str(), owner->getAuthServerProcessId(), ContainerInterface::getTopmostContainer(*recipient)->getNetworkId().getValueString().c_str(), recipient->getAuthServerProcessId() )); } } else if (recipient->getClient() == NULL) { // GameServer::getInstance().sendToPlanetServer( // GenericValueTypeMessage >( // "RequestSameServer", // std::make_pair( // ContainerInterface::getTopmostContainer(*owner)->getNetworkId(), // ContainerInterface::getTopmostContainer(*recipient)->getNetworkId())), // true); // transfer player to authoritative server //owner->transferAuthority(recipient->getAuthServerProcessId(), true, false); //owner->sendControllerMessageToAuthServer(CM_secureTrade, new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_RequestTrade, owner->getNetworkId(), data->getRecipient())); // try again next frame owner->sendControllerMessageToAuthServer(CM_secureTrade, new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_RequestTrade, owner->getNetworkId(), data->getRecipient())); } else if (!ServerSecureTradeManager::requestTradeWith(*owner, *recipient)) { MessageQueueSecureTrade * m = new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_DeniedPlayerBusy, owner->getNetworkId(), recipient->getNetworkId()); appendMessage(static_cast(CM_secureTrade), 0.0f, m, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); } } break; // we get this when the traders are on different servers, but the trade // initiator can't be moved to our server case MessageQueueSecureTrade::TMI_RequestTradeReversed: { CreatureObject * initiator = dynamic_cast(ServerWorld::findObjectByNetworkId(data->getInitiator())); if (!initiator) { DEBUG_REPORT_LOG(true, ("Could not find initiator for reversed secure trade message\n")); return; } if (! initiator->isAuthoritative()) { if (owner->isInWorldCell()) { // transfer player to authoritative server owner->transferAuthority(initiator->getAuthServerProcessId(), true, false, true); owner->sendControllerMessageToAuthServer(CM_secureTrade, new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_RequestTradeReversed, initiator->getNetworkId(), owner->getNetworkId())); } else { WARNING(true, ("Got TMI_RequestTradeReversed, but we are not in the world! Trade request abandoned.")); return; } } else initiator->sendControllerMessageToAuthServer(CM_secureTrade, new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_RequestTrade, initiator->getNetworkId(), owner->getNetworkId())); } break; case MessageQueueSecureTrade::TMI_TradeRequested: { WARNING_STRICT_FATAL(true, ("Server should not receive this message\n")); return; } break; case MessageQueueSecureTrade::TMI_AcceptTrade: { if (m_secureTrade || !m_secureTradeInitiator) { DEBUG_REPORT_LOG(true, ("Trade acceptance denied because of previous trade or failed startup steps\n")); return; } ServerSecureTradeManager::acceptTradeRequest(*m_secureTradeInitiator, *(static_cast(getOwner()))); m_secureTradeInitiator = 0; } break; case MessageQueueSecureTrade::TMI_DeniedTrade: { if (m_secureTrade || !m_secureTradeInitiator) { DEBUG_REPORT_LOG(true, ("Trade acceptance denied because of previous trade or failed startup steps\n")); return; } ServerSecureTradeManager::refuseTrade(*m_secureTradeInitiator, *(static_cast(getOwner()))); m_secureTradeInitiator = 0; } break; default: { DEBUG_REPORT_LOG(true, ("Unhandled secure trade message type\n")); } break; } } //---------------------------------------------------------- bool CreatureController::tradeRequested(CreatureObject & initiator) { //Check for outstanding trade requests. if (m_secureTradeInitiator || m_secureTrade) return false; m_secureTradeInitiator = &initiator; MessageQueueSecureTrade * m = new MessageQueueSecureTrade(MessageQueueSecureTrade::TMI_TradeRequested, initiator.getNetworkId(), getOwner()->getNetworkId()); appendMessage(static_cast(CM_secureTrade), 0.0f, m, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); return true; } //---------------------------------------------------------------------- void CreatureController::sendGenericResponse (int responseType, int requestType, bool success, uint8 sequenceId) { // send result back to player MessageQueueGenericResponse * response = new MessageQueueGenericResponse (requestType, success, sequenceId); appendMessage(responseType, 0.0f, response, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); } //---------------------------------------------------------------------- void CreatureController::steeringChanged() { return; } //----------------------------------------------------------------------- bool CreatureController::setSlopeModAngle(float angle) { CreatureObject * owner = static_cast(getOwner()); bool result = owner->setSlopeModAngle(angle); steeringChanged(); return result; } //----------------------------------------------------------------------- bool CreatureController::setSlopeModPercent(float percent) { CreatureObject * owner = static_cast(getOwner()); bool result = owner->setSlopeModPercent(percent); steeringChanged(); return result; } //----------------------------------------------------------------------- bool CreatureController::setWaterModPercent(float percent) { CreatureObject * owner = static_cast(getOwner()); bool result = owner->setWaterModPercent(percent); steeringChanged(); return result; } //----------------------------------------------------------------------- bool CreatureController::setMovementScale(float scale) { CreatureObject * owner = static_cast(getOwner()); return owner->setMovementScale(scale); } //----------------------------------------------------------------------- bool CreatureController::setMovementPercent(float percent) { CreatureObject * owner = static_cast(getOwner()); return owner->setMovementPercent(percent); } // ---------------------------------------------------------------------- bool CreatureController::setAccelScale(float scale) { CreatureObject * owner = static_cast(getOwner()); return owner->setAccelScale(scale); } //----------------------------------------------------------------------- bool CreatureController::setAccelPercent(float percent) { CreatureObject * owner = static_cast(getOwner()); return owner->setAccelPercent(percent); } // ---------------------------------------------------------------------- void CreatureController::setAppearanceFromObjectTemplate(std::string const &serverObjectTemplateName) { CreatureObject * owner = dynamic_cast(getOwner()); if (!owner) { WARNING(true, ("setAppearanceFromObjectTemplate(): owner is NULL or not a CreatureObject.")); return; } if (owner->isAuthoritative()) owner->setAlternateAppearance(serverObjectTemplateName); else owner->sendControllerMessageToAuthServer(CM_setAppearanceFromObjectTemplate, new MessageQueueGenericValueType(serverObjectTemplateName)); } //----------------------------------------------------------------------- CreatureObject * CreatureController::getCreature() { return safe_cast(getOwner()); } //----------------------------------------------------------------------- CreatureObject const * CreatureController::getCreature() const { return safe_cast(getOwner()); } // ---------------------------------------------------------------------- void CreatureController::endBaselines() { updateHibernate(); } // ---------------------------------------------------------------------- void CreatureController::updateHibernate() { if (getOwner()->isAuthoritative()) { setHibernate(shouldHibernate()); } } // ---------------------------------------------------------------------- bool CreatureController::shouldHibernate() const { if(!ConfigServerGame::getHibernateEnabled()) return false; // ---------- CreatureObject const * creature = getCreature(); NOT_NULL(creature); // If the creature is static, it hibernates. if(creature->getIsStatic()) return true; // If proxied creatures aren't allowed to hibernate and this creature is proxied, // it's not hibernating. if(!ConfigServerGame::getHibernateProxies() && (creature->getProxyCount() > 0)) return false; // if any players are observing me, don't hibernate return creature->getObserversCount() <= 0; } // ---------------------------------------------------------------------- bool CreatureController::getHibernate() const { CreatureObject const * owner = static_cast(getOwner()); return owner->hasCondition(ServerTangibleObjectTemplate::C_hibernating); } // ---------------------------------------------------------------------- void CreatureController::setHibernate(bool newHibernate) { bool oldHibernate = getHibernate(); if (oldHibernate == newHibernate) return; CreatureObject * owner = static_cast(getOwner()); if (!owner->isAuthoritative()) return; // ---------- bool transitionOk = true; if(newHibernate) { ScriptParams params; int result = getServerOwner()->getScriptObject()->trigAllScripts(Scripting::TRIG_HIBERNATE_BEGIN, params); if(result == SCRIPT_OVERRIDE) transitionOk = false; } else { ScriptParams params; int result = getServerOwner()->getScriptObject()->trigAllScripts(Scripting::TRIG_HIBERNATE_END, params); if(result == SCRIPT_OVERRIDE) transitionOk = false; } // ---------- if(transitionOk) { if(newHibernate) { // DEBUG_REPORT_LOG(true, ("[aitest] Hibernating %s\n", owner->getNetworkId().getValueString().c_str())); owner->setCondition(ServerTangibleObjectTemplate::C_hibernating); owner->setDefaultAlterTime(AlterResult::cms_keepNoAlter); } else { // DEBUG_REPORT_LOG(true, ("[aitest] Waking up %s\n", owner->getNetworkId().getValueString().c_str())); owner->clearCondition(ServerTangibleObjectTemplate::C_hibernating); if (owner->isPlayerControlled()) owner->setDefaultAlterTime(0); else owner->setDefaultAlterTime(AlterResult::cms_alterQuickly); } owner->scheduleForAlter(); // update the planet server for our hibernation change owner->updatePlanetServerInternal(true); } } //==================================================================== void CreatureController::calculateWaterState(bool& isSwimming, bool &isBurning, float& lavaResistance, float& waterHeight) const { //-- Mounts: if this is a rider, take the swim state from the mount. CreatureObject const *const ownerCreature = safe_cast(getOwner()); if (!ownerCreature) return; if (ownerCreature->getState(States::RidingMount)) { CreatureObject const *const mountCreature = ownerCreature->getMountedCreature(); CreatureController const *const mountCreatureController = mountCreature ? safe_cast(mountCreature->getController()) : NULL; if (mountCreatureController) { // Note: we do the real computation for the mount here because the rider gets // an alter prior to the mount. If we just checked the mount's swim state here, // we would be a frame behind on determining the player's swim state. mountCreatureController->calculateWaterState(isSwimming,isBurning,lavaResistance,waterHeight); return; } } //-- Determine if the owner is swimming. CollisionProperty const * const collisionProperty = ownerCreature->getCollisionProperty (); if (!collisionProperty) return; // JU_TODO: disabled - possibly make burning a persistant state #if 0 //-- Don't recompute if we're idle --- it shouldn't have changed. bool const isIdle = collisionProperty && collisionProperty->isIdle(); if (isIdle) return ownerCreature->getState(States::Swimming); #endif // JU_TODO: end disabled TerrainObject const * const terrainObject = TerrainObject::getConstInstance (); bool const isOnSolidFloor = collisionProperty && collisionProperty->getFootprint () && collisionProperty->getFootprint ()->isOnSolidFloor (); isSwimming = false; if (collisionProperty && ownerCreature->isInWorldCell () && !isOnSolidFloor) { Vector const position = ownerCreature->getPosition_w (); float terrainHeight; Footprint const * foot = collisionProperty->getFootprint(); lavaResistance = ownerCreature->getLavaResistance(); bool const isImmuneToLava = (lavaResistance == 100.0f); TerrainGeneratorWaterType waterType = terrainObject->getWaterType(position); if(!foot || !foot->getTerrainHeight(terrainHeight)) { if(!terrainObject->getHeight(position,terrainHeight)) { if(!terrainObject->getHeightForceChunkCreation(position,terrainHeight)) { return; } } } //-- see if the object is swimming and/or burning if (terrainObject->getWaterHeight (position, waterHeight)) { if(position.y - waterHeight < 1.0f && waterHeight >= terrainHeight) { float const swimHeight = ownerCreature->getSwimHeight (); isSwimming = (terrainHeight + swimHeight) < waterHeight; if(waterType == TGWT_lava) { isSwimming = false; if(!isImmuneToLava) { isBurning = true; } } } } } } // ---------------------------------------------------------------------- /** * Called when the owner CreatureObject has first been detected to start swimming. */ void CreatureController::onEnterSwimming() { CreatureObject *const owner = safe_cast(getOwner()); if (!owner) return; //-- Set the state to swimming. owner->setState(States::Swimming, true); //-- Fire off the script trigger indicating that the owner is now swimming. ScriptParams params; IGNORE_RETURN(owner->getScriptObject()->trigAllScripts(Scripting::TRIG_ENTER_SWIMMING, params)); } // ---------------------------------------------------------------------- /** * Called when the owner CreatureObject has first been detected to stop swimming. */ void CreatureController::onExitSwimming() { CreatureObject *const owner = safe_cast(getOwner()); if (!owner) return; //-- Clear the state to swimming. owner->setState(States::Swimming, false); //-- Fire off the script trigger indicating that the owner is no longer swimming. ScriptParams params; IGNORE_RETURN(owner->getScriptObject()->trigAllScripts(Scripting::TRIG_EXIT_SWIMMING, params)); } //---------------------------------------------------------------------- CreatureController * CreatureController::asCreatureController() { return this; } //---------------------------------------------------------------------- CreatureController const * CreatureController::asCreatureController() const { return this; } //---------------------------------------------------------------------- PlayerCreatureController * CreatureController::asPlayerCreatureController() { return NULL; } //---------------------------------------------------------------------- PlayerCreatureController const * CreatureController::asPlayerCreatureController() const { return NULL; } //---------------------------------------------------------------------- AICreatureController * CreatureController::asAiCreatureController() { return NULL; } //---------------------------------------------------------------------- AICreatureController const * CreatureController::asAiCreatureController() const { return NULL; } //----------------------------------------------------------------------- CreatureController * CreatureController::getCreatureController(NetworkId const & networkId) { return getCreatureController(NetworkIdManager::getObjectById(networkId)); } //----------------------------------------------------------------------- CreatureController * CreatureController::getCreatureController(Object * object) { Controller * controller = (object != NULL) ? object->getController() : NULL; return (controller != NULL) ? controller->asCreatureController() : NULL; } // ---------------------------------------------------------------------- CreatureController * CreatureController::asCreatureController(Controller * controller) { return (controller != NULL) ? controller->asCreatureController() : NULL; } // ---------------------------------------------------------------------- CreatureController const * CreatureController::asCreatureController(Controller const * controller) { return (controller != NULL) ? controller->asCreatureController() : NULL; } // ======================================================================