Example #1
0
void ObjectController::enqueueAutoAttack(uint64 targetId)
{
    if (mCommandQueue.empty())
    {
        uint32 sequence = 0;
        uint32 opcode = opOCattack;

        CreatureObject* creature = dynamic_cast<CreatureObject*>(mObject);
        if (!creature)
        {
            assert(false && "ObjectController::enqueueAutoAttack mObject is not a CreatureObject");
        }

        uint32	reply1 = 0;
        uint32	reply2 = 0;

        ObjectControllerCmdProperties* cmdProperties = NULL;


        if (_validateEnqueueCommand(reply1,reply2,targetId,opcode,cmdProperties))
        {
            ObjControllerCommandMessage* cmdMsg = new(mCmdMsgPool.malloc()) ObjControllerCommandMessage(opcode, cmdProperties->mDefaultTime, targetId);
            cmdMsg->setSequence(sequence);
            cmdMsg->setData(NULL);
            cmdMsg->setCmdProperties(cmdProperties);

            // Are there any cooldown left from previous command?
            uint64 now = Anh_Utils::Clock::getSingleton()->getLocalTime();
            if (mNextCommandExecution <= now)
            {
                uint64 underrun = now - mNextCommandExecution;

                if (underrun <= mUnderrunTime)
                {
                    mUnderrunTime -= underrun;
                }
                else
                {
                    mUnderrunTime = 0;
                }

                // This command are to be handled as fast as possible.
                mNextCommandExecution = now;
            }

            // add it
            mCommandQueue.push_front(cmdMsg);

            // add us to the scheduler, if we aren't queued already
            if(!mTaskId)
            {
                mTaskId = gWorldManager->addObjControllerToProcess(this);
            }
        }
        // not qualified for this command
        else
        {
            PlayerObject* player = dynamic_cast<PlayerObject*>(mObject);
            if (player)
            {
                player->disableAutoAttack();
                DLOG(INFO) << "ObjectController::enqueueAutoAttack() Error adding command.";
            }
        }
    }

}
Example #2
0
//=============================================================================
//
// incap
//
void CreatureObject::incap()
{
	// sanity check
	if (isIncapacitated() || isDead())
	{
		return;
	}

	if (this->getType() == ObjType_Player)
	{
		// gLogger->logMsgF("Player incapped, mIncapCount = %u.", MSG_NORMAL, mIncapCount);

		// first incap, update the initial time
		uint64 localTime = Anh_Utils::Clock::getSingleton()->getLocalTime();
		if(!mIncapCount)
		{
			mFirstIncapTime = localTime;
		}
		// reset the counter if the reset time has passed
		else if(mIncapCount != 0 && (localTime - mFirstIncapTime) >= gWorldConfig->getIncapResetTime() * 1000)
		{
			// gLogger->logMsgF("Time since first incap = %"PRIu64"", MSG_NORMAL, localTime - mFirstIncapTime);
			// gLogger->logMsgF("Resetting mFirstIncapTime", MSG_NORMAL);

			mIncapCount = 0;
			mFirstIncapTime = localTime;
		}
		/*
		if (mIncapCount != 0)
		{
			gLogger->logMsgF("Time since first incap = %"PRIu64"", MSG_NORMAL, localTime - mFirstIncapTime);
		}
		*/

		PlayerObject* player = dynamic_cast<PlayerObject*>(this);
		if (player)
		{
			player->disableAutoAttack();
		}

		//See if our player is mounted -- if so dismount him 
		if(player->checkIfMounted())
		{
			//Get the player's mount
			if(Vehicle* vehicle = dynamic_cast<Vehicle*>(gWorldManager->getObjectById(player->getMount()->getPetController())))
			{
				//Now dismount
				vehicle->dismountPlayer();
			}

		}

		// advance incaps counter
		if(++mIncapCount < gWorldConfig->getConfiguration("Player_Incapacitation",3))
		{
			// gLogger->logMsgF("Player incapped, mIncapCount set to = %u, setting timer..", MSG_NORMAL, mIncapCount);

			// update the posture
			mPosture = CreaturePosture_Incapacitated;

			// send timer updates
			mCurrentIncapTime = gWorldConfig->getBaseIncapTime() * 1000;
			gMessageLib->sendIncapTimerUpdate(this);

			// schedule recovery event
			mObjectController.addEvent(new IncapRecoveryEvent(),mCurrentIncapTime);

			// reset states
			mState = 0;

			// reset ham regeneration
			mHam.updateRegenRates();
			gWorldManager->removeCreatureHamToProcess(mHam.getTaskId());
			mHam.setTaskId(0);

			updateMovementProperties();

			gMessageLib->sendPostureAndStateUpdate(this);

			if(PlayerObject* player = dynamic_cast<PlayerObject*>(this))
			{
				gMessageLib->sendUpdateMovementProperties(player);
				gMessageLib->sendSelfPostureUpdate(player);
			}
		}
		// we hit the max -> death
		else
		{
			// gLogger->logMsgF("Player died.", MSG_NORMAL);
			die();
		}
	}
	else if (this->getType() == ObjType_Creature)	// A Creature.
	{
		die();
	}
	else
	{
		gLogger->logMsgF("CreatureObject::incap Incapped unsupported type %u\n", MSG_NORMAL, this->getType());
	}

}
Example #3
0
//=============================================================================
//
// process command queue
//
bool ObjectController::_processCommandQueue()
{
    mHandlerCompleted = false;
    // init timers
    uint64	startTime		= Anh_Utils::Clock::getSingleton()->getLocalTime();
    uint64	currentTime		= startTime;
    uint64	processTime		= 0;

    // uint64 currentTime = Anh_Utils::Clock::getSingleton()->getLocalTime();

    PlayerObject* player  = dynamic_cast<PlayerObject*>(mObject);
    if (!player)
    {
        assert(false && "ObjectController::_processCommandQueue mObject is not a PlayerObject");
        return false;
    }

    // If queue empty and we are in combat, insert player initiated auto-attack when the previous command has run out it's cooldown.
    if (mCommandQueue.empty() &&  player->autoAttackEnabled() && (mNextCommandExecution <= currentTime))
    {
        // Auto attack current target.
        uint64 autoTargetId = player->getCombatTargetId();
        if (autoTargetId != 0)
        {
            this->enqueueAutoAttack(autoTargetId);
        }
        else
        {
            player->disableAutoAttack();
        }
    }

    // For debug
    int16 loopCounter = 0;

    // loop until empty or our time is up
    while (!mCommandQueue.empty() && (processTime < mCommandQueueProcessTimeLimit))
    {
        mInUseCommandQueue = true;

        if (++loopCounter > 1)
        {
        }

        // see if we got something to execute yet
        ObjControllerCommandMessage* cmdMsg = mCommandQueue.front();

        // we might need to execute the command directly if it is part of the combat queue
        // and our queue execution timer permits it
        // or it is not part of the combat queue and can be executed directly in any case
        if ((mNextCommandExecution <= currentTime) || !cmdMsg->getCmdProperties()->mAddToCombatQueue)
        {
            if (cmdMsg->getCmdProperties()->mAddToCombatQueue)
            {
                // Compensate combat command for any lag, i.e. command arriving late.
                mUnderrunTime += (currentTime - mNextCommandExecution);
            }

            // get the commands data
            Message*	message		= cmdMsg->getData();	// Be aware, internally created messages are NULL (auto-attack)
            uint32		command		= cmdMsg->getOpcode();
            uint64		targetId	= cmdMsg->getTargetId();
            uint32		reply1		= 0;
            uint32		reply2		= 0;

            ObjectControllerCmdProperties*	cmdProperties = cmdMsg->getCmdProperties();

            // validate if we are still able to execute
            if (cmdProperties && _validateProcessCommand(reply1,reply2,targetId,command,cmdProperties))
            {

                // Do not mess with cooldowns for non combat commands, those timer values are for preventing spam of the same message,
                // and spam preventing is not implemented yet.
                uint64 timeToNextCommand = 0;
                if (cmdMsg->getCmdProperties()->mAddToCombatQueue)
                {
                    // Set up the cooldown time.
                    if (mUnderrunTime < cmdProperties->mDefaultTime)
                    {
                        timeToNextCommand = (cmdProperties->mDefaultTime - mUnderrunTime);
                        mUnderrunTime = 0;
                    }
                    else
                    {
                        // Compensate as much as we can.
                        timeToNextCommand = cmdProperties->mDefaultTime / 2;
                        mUnderrunTime -= timeToNextCommand;
                    }
                }

                // keep a pointer to the start
                uint16	paramsIndex = 0;
                if (message)
                {
                    paramsIndex = message->getIndex();
                }

                bool cmdExecutedOk = true;

                // call the proper handler
                switch(cmdProperties->mCmdGroup)
                {
                case ObjControllerCmdGroup_Common:
                {
                    // Check the new style of handlers first.
                    CommandMap::const_iterator it = gObjectControllerCommands->getCommandMap().find(command);

                    // Find the target object (if one is given) and pass it in.
                    Object* target = NULL;

                    if (targetId) {
                        target = gWorldManager->getObjectById(targetId);
                    }

                    // If a new style handler is found process it.
                    if (message && it != gObjectControllerCommands->getCommandMap().end()) {
                        // Create a pre-command processing event.
                        auto pre_event = std::make_shared<PreCommandEvent>(mObject->getId());
                        pre_event->target_id(targetId);
                        pre_event->command_crc(cmdProperties->mCmdCrc);

                        // Trigger a pre-command processing event and get the result. This allows
                        // any listeners to veto the processing of the command (such as validators).
                        // Only process the command if it passed validation.
                        if (gEventDispatcher.Deliver(pre_event).get()) {
                            ((*it).second)(mObject, target, message, cmdProperties);

                            auto post_event = std::make_shared<PostCommandEvent>(mObject->getId());
                            gEventDispatcher.Deliver(post_event);
                        }
                    } else {
                        // Otherwise, process the old style handler.
                        OriginalCommandMap::iterator it = gObjControllerCmdMap.find(command);

                        if (message && it != gObjControllerCmdMap.end()) {
                            ((*it).second)(this, targetId, message, cmdProperties);
                            //(this->*((*it).second))(targetId,message,cmdProperties);
                        } else {
                            DLOG(WARNING) << "ObjectController::processCommandQueue: ObjControllerCmdGroup_Common Unhandled Cmd 0"<<command<<" for "<<mObject->getId();
                            //gLogger->hexDump(message->getData(),message->getSize());
                        }
                    }
                }
                break;
                case ObjControllerCmdGroup_Attack:
                {
                    // If player activated combat or me returning fire, the peace is ended, and auto-attack allowed.
                    gStateManager.setCurrentActionState(player, CreatureState_Combat);
                    // TODO: add auto attack to enter combat state.
                    player->enableAutoAttack();

                    // CreatureObject* creature = NULL;
                    if (targetId != 0)
                    {
                        cmdExecutedOk = gCombatManager->handleAttack(player, targetId, cmdProperties);
                        if (!cmdExecutedOk)
                        {
                            // We have lost our target.
                            player->setCombatTargetId(0);
                            player->disableAutoAttack();
                        }
                        else
                        {
                            // All is well in la-la-land
                            // Keep track of the target we are attacking, it's not always your "look-at" target.
                            if (targetId != player->getCombatTargetId() && (targetId != 0))
                            {
                                // We have a new target
                                // new target still valid?
                                if (player->setAsActiveDefenderAndUpdateList(targetId))
                                {
                                    player->setCombatTargetId(targetId);
                                }
                                else
                                {
                                    player->disableAutoAttack();
                                    player->setCombatTargetId(0);
                                }
                            }
                            else
                            {
                                player->setCombatTargetId(targetId);
                            }
                        }
                    }
                    else
                    {
                        cmdExecutedOk = false;
                        player->setCombatTargetId(0);
                    }
                }
                break;

                default:
                {
					DLOG(WARNING) << "ObjectController::processCommandQueue: ObjControllerCmdGroup_Common Unhandled Cmd 0"<<cmdProperties->mCmdGroup <<" for "<<mObject->getId();
                }
                break;
                }

                // Do not mess with cooldowns for non combat commands...
                if (cmdMsg->getCmdProperties()->mAddToCombatQueue)
                {
                    if (cmdExecutedOk)
                    {
                        mNextCommandExecution = currentTime + timeToNextCommand;
                    }
                    else
                    {
                        // we will not spam the command queue if auto-attack is set to an invalid target.
                        mNextCommandExecution = currentTime;
                    }
                }

                // execute any attached scripts
                if (message)	// Auto-attack commands have no message body.
                {
                    BString params;
                    message->setIndex(paramsIndex);
                    message->getStringUnicode16(params);
                    params.convert(BSTRType_ANSI);

                    gObjectControllerCommands->mCmdScriptListener.handleScriptEvent(cmdProperties->mCommandStr.getAnsi(),params);
                }
            }

            //its processed, so ack and delete it
            if (message && cmdMsg->getSequence())
            {
                // if (PlayerObject* player = dynamic_cast<PlayerObject*>(mObject))
                gMessageLib->sendCommandQueueRemove(cmdMsg->getSequence(),(static_cast<float>(cmdMsg->getExecutionTime())/1000),reply1,reply2,player);
            }

            // Be aware, internally created messages are NULL (auto-attack)
            if (message)
            {
                message->setPendingDelete(true);
            }
            // Remove the command from queue. Note: pop() invokes object destructor.
            mCommandQueue.pop_front();

            // cmdMsg->~ObjControllerCommandMessage();
            mCmdMsgPool.free(cmdMsg);
        }
        else
        {
            // Make it simple, the time was not up yet, just leave, let other instances have the cpu, and handle it the next cycle.
            break;
        }

        // update timers
        currentTime = Anh_Utils::Clock::getSingleton()->getLocalTime();
        processTime = currentTime - startTime;
    }

    // if we didn't manage to process all or theres an event still waiting, don't remove us from the scheduler
    // We need to keep the queue as long as we are in combat.

    mInUseCommandQueue = false;

    if (mRemoveCommandQueue)
    {
        this->clearQueues();
    }
    return ((!mCommandQueue.empty() ||  player->autoAttackEnabled())? true : false);
}