HowTo Add a NPC Operation: Difference between revisions

From PSwiki
Jump to navigation Jump to search
Naeg (talk | contribs)
No edit summary
Naeg (talk | contribs)
No edit summary
Line 1: Line 1:
== Summary ==
== Summary ==
NOTE: In Work


# Create new Operation Class in npcclient/npcoperations
# Create new Operation Class in npcclient/npcoperations
# Create new Queue-Command in npcclient/networkmgr
# Create new Queue-Command in npcclient/networkmgr
# Modify net/npcmessages
# Modify common/net/npcmessages
# Process Command in npcclient/npcmanager and execute desired action
# Process Command in npcclient/npcmanager and execute desired action
=== New Operation Class ===
Example: LootOperation
src/npcclient/npcoperations.h
<code>
<nowiki>
/** Loot will make the NPC loot specified items
*
*  This class is the implementation of the loot operations
*  used in behavior scripts for NPCS.
*
*  Examples: <pre>
*  \<loot type="all"    /\>
*  \<loot type="weapons" /\> </pre>
*/
class LootOperation : public ScriptOperation
{
protected:
    csString type; ///< Type of items to loot
public:
    LootOperation(): ScriptOperation("Loot") {};
    virtual ~LootOperation() {};
    virtual OperationResult Run(NPC* npc,bool interrupted);
    virtual bool Load(iDocumentNode* node);
    virtual ScriptOperation* MakeCopy();
};</nowiki></code>
src/npcclient/npcoperations.cpp
<code>
<nowiki>
bool LootOperation::Load(iDocumentNode *node)
{
    type = node->GetAttributeValue("type");
   
    if(type.IsEmpty())
        type = "all"
   
    return true;
}
ScriptOperation* LootOperation::MakeCopy()
{
    LootOperation* op = new LootOperation;
    op->type = type;
    return op;
}
ScriptOperation::OperationResult LootOperation::Run(NPC *npc, bool interrupted)
{
    npcclient->GetNetworkMgr()->QueueLootCommand(npc->GetActor(), type);
   
    return OPERATION_COMPLETED; // Nothing more to do for this op.
}</nowiki></code>
=== New Queue-Command ===
src/npcclient/networkmgr.h
<code>
<nowiki>
    /**
    * Send a command to loot selected target.
    */
    void QueueLootCommand(gemNPCActor *entity, const csString& type);</nowiki></code>
src/npcclient/networkmgr.cpp
<code>
<nowiki>
void NetworkManager::QueueLootCommand(gemNPCActor *entity, const csString& type);
{
    CheckCommandsOverrun(sizeof(uint8_t) + sizeof(uint32_t) + (type.Length()+1));
    outbound->msg->Add((int8_t) psNPCCommandsMessage::CMD_LOOT);
    outbound->msg->Add(entity->GetEID().Unbox());
    outbound->msg->Add(type);
    if(outbound->msg->overrun)
    {
        CS_ASSERT(!"NetworkManager::QueueLootCommand put message in overrun state!\n");
    }
    cmd_count++;
}</nowiki></code>
=== Modify npcmessages ===
Add new CMD to PerceptionType:
src/common/net/npcmessages.h
<code>
<nowiki>
    enum PerceptionType
    {
        // Commands go from superclient to server
        // [...]
        CMD_CONTROL,
CMD_LOOT, // new CMD for looting
        // Perceptions go from server to superclient
        PCPT_ANYRANGEPLAYER,
        // [...]
    };</nowiki></code>
Add new case to psNPCCOmmandsMessage::ToString():
src/common/net/npcmessages.cpp
<code>
<nowiki>
csString psNPCCommandsMessage::ToString(NetBase::AccessPointers * accessPointers)
{
    // [...]
    case psNPCCommandsMessage::CMD_LOOT:
            {
                msgtext.Append("CMD_LOOT: ");
                // Extract the data
                EID entity_id = EID(msg->GetUInt32());
                csString type = msg->GetStr();
                // Make sure we haven't run past the end of the buffer
                if(msg->overrun)
                {
                    Debug2(LOG_SUPERCLIENT,msg->clientnum,"Received incomplete CMD_LOOT from NPC client %u.\n",msg->clientnum);
                    break;
                }
               
                msgtext.AppendFmt("EID: %u Type: %s", entity_id.Unbox(), type.GetData());
                break;
            }
            // [...]
}</nowiki></code>
=== Process Command ===
Add case for new Command in NPCManager::HandleCommandList():
src/npcclient/npcmanager.cpp
<code>
<nowiki>
void NPCManager::HandleCommandList(MsgEntry* me,Client* client)
{
    // [...]
            case psNPCCommandsMessage::CMD_LOOT:
            {
                EID entity_id = EID(list.msg->GetUInt32());
                csString type = list.msg->GetStr();
                Debug4(LOG_SUPERCLIENT, entity_id.Unbox(), "-->Got loot cmd: Entity %s to loot for %s\n",
                      ShowID(entity_id), type.GetData());
                // Make sure we haven't run past the end of the buffer
                if(list.msg->overrun)
                {
                    Debug2(LOG_SUPERCLIENT, entity_id.Unbox(), "Received incomplete CMD_LOOT from NPC client %u.\n", me->clientnum);
                    break;
                }
                gemNPC* npc = dynamic_cast<gemNPC*>(gemSupervisor->FindObject(entity_id));
               
                /*  NEEDED?
                psCharacter* chardata = NULL;
               
                if(npc) chardata = npc->GetCharacterData();
               
                if(!chardata)
                {
                    Debug1(LOG_SUPERCLIENT, entity_id.Unbox(), "Couldn't find character data.\n");
                    break;
                }*/
               
                if(npc)
                {
                    psserver->GetUserManager()->LootMoney(client);
                    psserver->GetUserManager()->LootItems(client, type);
                   
                    if(npc->GetTribeID())
                    {
                        // add loot to tribe's resources
                    }
                }
                else
                    Error1("NPC Client try to loot with no existing npc");
               
                break;
            }
        // [...]
}</nowiki></code>


[[Category:Engine documents]] [[Category:NPCClient Design]]
[[Category:Engine documents]] [[Category:NPCClient Design]]

Revision as of 17:11, 1 April 2013

Summary

NOTE: In Work

  1. Create new Operation Class in npcclient/npcoperations
  2. Create new Queue-Command in npcclient/networkmgr
  3. Modify common/net/npcmessages
  4. Process Command in npcclient/npcmanager and execute desired action

New Operation Class

Example: LootOperation

src/npcclient/npcoperations.h

/** Loot will make the NPC loot specified items
 *
 *  This class is the implementation of the loot operations
 *  used in behavior scripts for NPCS.
 *
 *  Examples: <pre>
 *  \<loot type="all"     /\>
 *  \<loot type="weapons" /\> </pre>
 */
class LootOperation : public ScriptOperation
{
protected:
    csString type; ///< Type of items to loot

public:

    LootOperation(): ScriptOperation("Loot") {};
    virtual ~LootOperation() {};
    virtual OperationResult Run(NPC* npc,bool interrupted);
    virtual bool Load(iDocumentNode* node);
    virtual ScriptOperation* MakeCopy();
};

src/npcclient/npcoperations.cpp

bool LootOperation::Load(iDocumentNode *node)
{
    type = node->GetAttributeValue("type");
    
    if(type.IsEmpty())
        type = "all"
    
    return true;
}

ScriptOperation* LootOperation::MakeCopy()
{
    LootOperation* op = new LootOperation;

    op->type = type;

    return op;
}

ScriptOperation::OperationResult LootOperation::Run(NPC *npc, bool interrupted)
{
    npcclient->GetNetworkMgr()->QueueLootCommand(npc->GetActor(), type);
    
    return OPERATION_COMPLETED; // Nothing more to do for this op.
}

New Queue-Command

src/npcclient/networkmgr.h

    /**
     * Send a command to loot selected target.
     */
    void QueueLootCommand(gemNPCActor *entity, const csString& type);

src/npcclient/networkmgr.cpp

void NetworkManager::QueueLootCommand(gemNPCActor *entity, const csString& type);
{
    CheckCommandsOverrun(sizeof(uint8_t) + sizeof(uint32_t) + (type.Length()+1));

    outbound->msg->Add((int8_t) psNPCCommandsMessage::CMD_LOOT);
    outbound->msg->Add(entity->GetEID().Unbox());
    outbound->msg->Add(type);

    if(outbound->msg->overrun)
    {
        CS_ASSERT(!"NetworkManager::QueueLootCommand put message in overrun state!\n");
    }

    cmd_count++;
}

Modify npcmessages

Add new CMD to PerceptionType:

src/common/net/npcmessages.h

    enum PerceptionType
    {
        // Commands go from superclient to server
        // [...]
        CMD_CONTROL,
	CMD_LOOT, // new CMD for looting
        // Perceptions go from server to superclient
        PCPT_ANYRANGEPLAYER,
        // [...]
    };

Add new case to psNPCCOmmandsMessage::ToString():

src/common/net/npcmessages.cpp

csString psNPCCommandsMessage::ToString(NetBase::AccessPointers * accessPointers)
{
    // [...]

	    case psNPCCommandsMessage::CMD_LOOT:
            {
                msgtext.Append("CMD_LOOT: ");

                // Extract the data
                EID entity_id = EID(msg->GetUInt32());
                csString type = msg->GetStr();

                // Make sure we haven't run past the end of the buffer
                if(msg->overrun)
                {
                    Debug2(LOG_SUPERCLIENT,msg->clientnum,"Received incomplete CMD_LOOT from NPC client %u.\n",msg->clientnum);
                    break;
                }
                
                msgtext.AppendFmt("EID: %u Type: %s", entity_id.Unbox(), type.GetData());
                break;
            }
            // [...]
}

Process Command

Add case for new Command in NPCManager::HandleCommandList():

src/npcclient/npcmanager.cpp

void NPCManager::HandleCommandList(MsgEntry* me,Client* client)
{
    // [...]
            case psNPCCommandsMessage::CMD_LOOT:
            {
                EID entity_id = EID(list.msg->GetUInt32());
                csString type = list.msg->GetStr();
                Debug4(LOG_SUPERCLIENT, entity_id.Unbox(), "-->Got loot cmd: Entity %s to loot for %s\n",
                       ShowID(entity_id), type.GetData());

                // Make sure we haven't run past the end of the buffer
                if(list.msg->overrun)
                {
                    Debug2(LOG_SUPERCLIENT, entity_id.Unbox(), "Received incomplete CMD_LOOT from NPC client %u.\n", me->clientnum);
                    break;
                }

                gemNPC* npc = dynamic_cast<gemNPC*>(gemSupervisor->FindObject(entity_id));
                
                /*  NEEDED?
                psCharacter* chardata = NULL;
                
                if(npc) chardata = npc->GetCharacterData();
                
                if(!chardata)
                {
                    Debug1(LOG_SUPERCLIENT, entity_id.Unbox(), "Couldn't find character data.\n");
                    break;
                }*/
                
                if(npc)
                {
                    psserver->GetUserManager()->LootMoney(client);
                    psserver->GetUserManager()->LootItems(client, type);
                    
                    if(npc->GetTribeID())
                    {
                        // add loot to tribe's resources
                    }
                }
                else
                     Error1("NPC Client try to loot with no existing npc");
                
                break;
            }
        // [...]
}