HowTo Add a NPC Operation: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
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
- Create new Operation Class in npcclient/npcoperations
- Create new Queue-Command in npcclient/networkmgr
- Modify common/net/npcmessages
- 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;
}
// [...]
}