From: <ma...@us...> - 2012-08-11 20:26:01
|
Revision: 8421 http://planeshift.svn.sourceforge.net/planeshift/?rev=8421&view=rev Author: magodra Date: 2012-08-11 20:25:53 +0000 (Sat, 11 Aug 2012) Log Message: ----------- - Added new <script name="script" /> NPC operation. - Added new <unbuild /> NPC operation. - Added new <set_buffer type="npc|tribe" buffer="buffer" value="value" /> NPC operation. - Added building to the NPC operation locate for object type. Eg. <locate obj="building" .../> - Added ToString for the psPersistAllEntities message sent to npcclient at startup - Added UID to the psPersistItem message that will only be distributed to NPCclient. - Added handling of persist of item and connect them to tribe assets using weak refs. - Change the tribe asset itemName field to a itemID field. - Added deleate of not used Assets - Fixed building and item requirements for NPC receips to only add new receipes for the number of items missing. - Added npcclient command setbuffer <npc> <buffer> <value> Modified Paths: -------------- trunk/src/common/net/messages.cpp trunk/src/common/net/messages.h trunk/src/common/net/npcmessages.cpp trunk/src/common/net/npcmessages.h trunk/src/npcclient/command.cpp trunk/src/npcclient/gem.cpp trunk/src/npcclient/gem.h trunk/src/npcclient/networkmgr.cpp trunk/src/npcclient/networkmgr.h trunk/src/npcclient/npcbehave.cpp trunk/src/npcclient/npcclient.cpp trunk/src/npcclient/npcoperations.cpp trunk/src/npcclient/npcoperations.h trunk/src/npcclient/recipe.cpp trunk/src/npcclient/tribe.cpp trunk/src/npcclient/tribe.h trunk/src/server/database/mysql/command_access.sql trunk/src/server/database/mysql/sc_npctypes.sql trunk/src/server/database/mysql/sc_tribe_assets.sql trunk/src/server/database/mysql/server_options.sql trunk/src/server/database/mysql/upgrade_schema.sql trunk/src/server/gem.cpp trunk/src/server/npcmanager.cpp trunk/src/server/psserver.cpp Modified: trunk/src/common/net/messages.cpp =================================================================== --- trunk/src/common/net/messages.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/common/net/messages.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -4948,9 +4948,37 @@ msg = me; } -csString psPersistAllEntities::ToString(NetBase::AccessPointers* /*accessPointers*/) +csString psPersistAllEntities::ToString(NetBase::AccessPointers* accessPointers) { - return "PersistAllEntities"; + csString msgtext; + while (true) + { + MsgEntry *entity = GetEntityMessage(); + if (!entity) break; + + if (entity->GetType() == MSGTYPE_PERSIST_ACTOR) + { + psPersistActor mesg( entity, accessPointers, true ); + msgtext += " Actor: "; + msgtext += mesg.ToString( accessPointers ); + msgtext += "\n"; + } + else if (entity->GetType() == MSGTYPE_PERSIST_ITEM) + { + psPersistItem mesg( entity, accessPointers ); + msgtext += " Item: "; + msgtext += mesg.ToString( accessPointers ); + msgtext += "\n"; + } + else + { + Error2("Unhandled type of entity (%d) in AllEntities message.",entity->GetType() ); + } + + delete entity; + } + + return msgtext; } bool psPersistAllEntities::AddEntityMessage(MsgEntry *newEnt) @@ -5196,7 +5224,8 @@ float zRot, uint32_t flags, csStringSet* msgstrings, - uint32_t tribeID) + uint32_t tribeID, + uint32_t uid) { msg.AttachNew(new MsgEntry( MAX_MESSAGE_SIZE )); @@ -5217,6 +5246,10 @@ { flags |= TRIBEID; } + if (uid != 0) + { + flags |= ITEM_UID; + } if (flags) // No point sending 0, only enties called out by flags can follow { msg->Add( flags ); @@ -5226,6 +5259,10 @@ { msg->Add(tribeID); } + if (flags & ITEM_UID) + { + msg->Add(uid); + } msg->ClipToCurrentSize(); } @@ -5251,6 +5288,10 @@ { tribeID = me->GetInt32(); } + if (flags & ITEM_UID) + { + uid = me->GetUInt32(); + } } } @@ -5270,6 +5311,11 @@ msgtext.AppendFmt(" TRIBEID"); msgtext.AppendFmt(" Belongs to tribe: (id:%d)\n", tribeID); } + if(flags & ITEM_UID) + { + msgtext.AppendFmt(" ITEM_UID"); + msgtext.AppendFmt(" uid: %d\n", uid); + } return msgtext; } Modified: trunk/src/common/net/messages.h =================================================================== --- trunk/src/common/net/messages.h 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/common/net/messages.h 2012-08-11 20:25:53 UTC (rev 8421) @@ -3299,7 +3299,8 @@ NONE = 0, NOPICKUP = 1 << 0, COLLIDE = 1 << 1, - TRIBEID = 1 << 2 + TRIBEID = 1 << 2, + ITEM_UID = 1 << 3 }; psPersistItem(uint32_t clientnum, @@ -3315,7 +3316,8 @@ float zRot, uint32_t flags, csStringSet* msgstrings, - uint32_t tribeid = 0 + uint32_t tribeid = 0, + uint32_t uid = 0 ); psPersistItem(MsgEntry* me, NetBase::AccessPointers* accessPointers); @@ -3342,6 +3344,7 @@ EID eid; uint32_t type; uint32_t flags; + uint32_t uid; }; class psPersistActionLocation : public psMessageCracker Modified: trunk/src/common/net/npcmessages.cpp =================================================================== --- trunk/src/common/net/npcmessages.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/common/net/npcmessages.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -370,6 +370,25 @@ msgtext.AppendFmt("Attacker: %s Target: %s Spell: %s kFactor: %.1f", ShowID(attackerEID), ShowID(targetEID),spell.GetDataSafe(),kFactor); break; } + case psNPCCommandsMessage::CMD_SCRIPT: + { + msgtext.Append("CMD_SCRIPT: "); + + // Extract the data + EID npcEID = EID(msg->GetUInt32()); + EID targetEID = EID(msg->GetUInt32()); + csString scriptName = 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_SCRIPT from NPC client %u.\n",msg->clientnum); + break; + } + + msgtext.AppendFmt("NPC: %u Target: %u To: %s", npcEID.Unbox(), targetEID.Unbox(), scriptName.GetDataSafe()); + break; + } case psNPCCommandsMessage::CMD_SIT: { msgtext.Append("CMD_SIT: "); @@ -426,7 +445,7 @@ } msgtext.AppendFmt("Spawner: %s Pos: %s in sectorName %s. TribeID: %d. Building: %s", ShowID(spawnerEID), toString(pos).GetDataSafe(), sectorName.GetDataSafe(), tribeID, buildingName.GetDataSafe()); - + break; } case psNPCCommandsMessage::CMD_TALK: { @@ -450,6 +469,23 @@ speaker_id.Unbox(), targetId.Unbox(), talkType, publicTalk?"Yes":"No", text); break; } + case psNPCCommandsMessage::CMD_UNBUILD: + { + msgtext.Append("CMD_UNBUILD: "); + + //Extract the data + EID unbuilderEID = EID(msg->GetUInt32()); + EID buildingEID = EID(msg->GetUInt32()); + + if(msg->overrun) + { + Debug2(LOG_SUPERCLIENT, msg->clientnum, "Received incomplete CMD_UNBUILD from NPC client %u.\n", msg->clientnum); + break; + } + + msgtext.AppendFmt("Unbuilder: %s Building: %s", ShowID(unbuilderEID), ShowID(buildingEID)); + break; + } case psNPCCommandsMessage::CMD_VISIBILITY: { msgtext.Append("CMD_VISIBILITY: "); Modified: trunk/src/common/net/npcmessages.h =================================================================== --- trunk/src/common/net/npcmessages.h 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/common/net/npcmessages.h 2012-08-11 20:25:53 UTC (rev 8421) @@ -218,11 +218,13 @@ CMD_PICKUP, CMD_RESURRECT, CMD_SEQUENCE, + CMD_SCRIPT, // used for superclient to request a progress script to be run at server CMD_SIT, CMD_SPAWN, CMD_SPAWN_BUILDING, // used for superclient to request a new building CMD_TALK, CMD_TRANSFER, + CMD_UNBUILD, // used for superclient to request a building to be tearn down CMD_VISIBILITY, CMD_WORK, CMD_CONTROL, Modified: trunk/src/npcclient/command.cpp =================================================================== --- trunk/src/npcclient/command.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/command.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -340,6 +340,32 @@ return 0; } +int com_setbuffer(const char*line) +{ + WordArray words(line,false); + + if (!*line || words.GetCount() != 3) + { + CPrintf(CON_CMDOUTPUT, "Please specify: <npc_id> <buffer_name> <buffer_value>\n"); + return 0; + } + + + unsigned int id = atoi(words[0]); + NPC* npc = npcclient->FindNPCByPID(id); + if(!npc) + { + CPrintf(CON_CMDOUTPUT, "No NPC with id '%s' found.\n", words[0].GetDataSafe()); + return 0; + } + + npc->SetBuffer(words[1],words[2]); + + CPrintf(CON_CMDOUTPUT, "Setting buffer %s to %s for NPC %s.\n", words[1].GetDataSafe(), words[2].GetDataSafe(), npc->GetName()); + + return 0; +} + int com_setlog(const char* line) { if (!*line) @@ -435,10 +461,11 @@ { "filtermsg", true, com_filtermsg, "Add or remove messages from the LOG_MESSAGE log"}, { "fireperc", false, com_fireperc, "Fire the given perception on the given npc. (fireperc [npcPID] [perception])"}, { "help", false, com_help, "Show help information" }, + { "info", false, com_info, "Short print for 1 NPC"}, { "list", false, com_list, "List entities ( list [char|ent|loc|npc|path|race|recipe|tribe|warpspace|waypoint] <filter> )" }, { "print", false, com_print, "List all behaviors/hate of 1 NPC"}, - { "info", false, com_info, "Short print for 1 NPC"}, { "quit", true, com_quit, "Makes the npc client exit"}, + { "setbuffer", false, com_setbuffer, "Set a npc buffer"}, { "setlog", false, com_setlog, "Set server log" }, { "setmaxfile", false, com_setmaxfile, "Set maximum message class for output file"}, { "setmaxout", false, com_setmaxout, "Set maximum message class for standard output"}, Modified: trunk/src/npcclient/gem.cpp =================================================================== --- trunk/src/npcclient/gem.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/gem.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -260,6 +260,8 @@ name = mesg.name; Debug3(LOG_CELPERSIST, 0, "Item %s(%s) Received", mesg.name.GetData(), ShowID(mesg.eid)); type = mesg.type; + uid = mesg.uid; + tribeID = mesg.tribeID; if(!mesg.factname.GetData()) { @@ -270,12 +272,24 @@ if (mesg.flags & psPersistItem::NOPICKUP) flags |= NOPICKUP; } +gemNPCItem::~gemNPCItem() +{ +} + //Here we check the flag to see if we can pick up this item bool gemNPCItem::IsPickable() { return !(flags & NOPICKUP); } -gemNPCItem::~gemNPCItem() +uint32_t gemNPCItem::GetUID() const { + return uid; } + +uint32_t gemNPCItem::GetTribeID() const +{ + return tribeID; +} + + Modified: trunk/src/npcclient/gem.h =================================================================== --- trunk/src/npcclient/gem.h 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/gem.h 2012-08-11 20:25:53 UTC (rev 8421) @@ -183,7 +183,12 @@ virtual bool IsPickable(); + uint32_t GetUID() const; + uint32_t GetTribeID() const; + protected: + uint32_t uid; + uint32_t tribeID; int flags; }; Modified: trunk/src/npcclient/networkmgr.cpp =================================================================== --- trunk/src/npcclient/networkmgr.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/networkmgr.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -419,17 +419,6 @@ gemNPCItem* item = new gemNPCItem(npcclient, mesg); npcclient->Add(item); - // Is this a tribe Item? - if(mesg.tribeID != 0) - { - csVector3 where; - Tribe* tribe = npcclient->GetTribe(mesg.tribeID); - if(tribe) - { - tribe->HandlePersitItem(item); - } - } - } void NetworkManager::HandleObjectRemoval( MsgEntry* me ) @@ -1752,6 +1741,29 @@ cmd_count++; } +void NetworkManager::QueueScriptCommand(gemNPCActor *npc, gemNPCObject* target, const csString& scriptName) +{ + CheckCommandsOverrun(100); + + outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_SCRIPT); + outbound->msg->Add( npc->GetEID().Unbox() ); + if (target) + { + outbound->msg->Add( target->GetEID().Unbox() ); + } + else + { + outbound->msg->Add( (uint32_t)0 ); + } + outbound->msg->Add( scriptName ); + + if ( outbound->msg->overrun ) + { + CS_ASSERT(!"NetworkManager::QueueScriptCommand put message in overrun state!\n"); + } + cmd_count++; +} + void NetworkManager::QueueSitCommand(gemNPCActor *npc, gemNPCObject* target, bool sit) { CheckCommandsOverrun(100); @@ -1810,6 +1822,21 @@ cmd_count++; } +void NetworkManager::QueueUnbuildCommand(gemNPCActor *unbuilder, gemNPCItem* building) +{ + CheckCommandsOverrun(100); + + outbound->msg->Add((int8_t) psNPCCommandsMessage::CMD_UNBUILD); + outbound->msg->Add(unbuilder->GetEID().Unbox()); + outbound->msg->Add(building->GetEID().Unbox()); + + if(outbound->msg->overrun) + { + CS_ASSERT(!"NetworkManager::QueueUnbuildingCommand put message in overrun state!\n"); + } + cmd_count++; +} + void NetworkManager::QueueTalkCommand(gemNPCActor *speaker, gemNPCActor* target, psNPCCommandsMessage::PerceptionTalkType talkType, bool publicTalk, const char* text) { CheckCommandsOverrun(100); Modified: trunk/src/npcclient/networkmgr.h =================================================================== --- trunk/src/npcclient/networkmgr.h 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/networkmgr.h 2012-08-11 20:25:53 UTC (rev 8421) @@ -43,6 +43,7 @@ class NPC; class gemNPCActor; class gemNPCObject; +class gemNPCItem; class NetworkManager : public psClientNetSubscriber @@ -136,6 +137,14 @@ */ void QueueAttackCommand(gemNPCActor *attacker, gemNPCActor *target, const char* stance); + /** Send a script command to server + * + * @param npc The npc that sit/stand + * @param target The current target of then npc + * @param scriptName The name of the progression script to run at server + */ + void QueueScriptCommand(gemNPCActor *npc, gemNPCObject *target, const csString& scriptName); + /** Send a sit command to server * * @param npc The npc that sit/stand @@ -161,6 +170,13 @@ * @param tribeID The owner of this building */ void QueueSpawnBuildingCommand(gemNPCActor *spawner, csVector3 where, iSector* sector, const char* buildingName, int tribeID); + + /** Send a unbuild command to server + * + * @param unbuilder The entity that unbuild the building + * @param building The building. + */ + void QueueUnbuildCommand(gemNPCActor *unbuilder, gemNPCItem* building); /** Queue a talk command to the server * Modified: trunk/src/npcclient/npcbehave.cpp =================================================================== --- trunk/src/npcclient/npcbehave.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/npcbehave.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -1172,10 +1172,18 @@ { op = new RotateOperation; } + else if ( strcmp( node->GetValue(), "script" ) == 0 ) + { + op = new ProgressScriptOperation; + } else if ( strcmp( node->GetValue(), "sequence" ) == 0 ) { op = new SequenceOperation; } + else if ( strcmp( node->GetValue(), "set_buffer" ) == 0 ) + { + op = new SetBufferOperation; + } else if ( strcmp( node->GetValue(), "share_memories" ) == 0 ) { op = new ShareMemoriesOperation; @@ -1208,6 +1216,10 @@ { op = new TribeTypeOperation; } + else if ( strcmp( node->GetValue(), "unbuild" ) == 0 ) + { + op = new UnbuildOperation; + } else if ( strcmp( node->GetValue(), "visible" ) == 0 ) { op = new VisibleOperation; Modified: trunk/src/npcclient/npcclient.cpp =================================================================== --- trunk/src/npcclient/npcclient.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/npcclient.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -587,6 +587,28 @@ if (item) { all_gem_items.Push( item ); + + // Is this a tribe Item with tribe ID? + if (item->GetTribeID() != 0) + { + Tribe* tribe = GetTribe(item->GetTribeID()); + if(tribe) + { + tribe->HandlePersistItem(item); + } + } + else + { + // Is this an asset without tribe ID? + for (size_t i=0; i<tribes.GetSize(); i++) + { + Tribe::Asset* asset = tribes[i]->GetAsset(item->GetUID()); + if (asset) + { + asset->item = item; + } + } + } } gemNPCActor* actor = dynamic_cast<gemNPCActor*>(object); @@ -634,6 +656,33 @@ { all_gem_items.DeleteIndexFast( n ); } + + Tribe::Asset* asset = NULL; + Tribe* tribe = NULL; + // Is this a tribe Item with tribe ID? + if (item->GetTribeID() != 0) + { + tribe = GetTribe(item->GetTribeID()); + if(tribe) + { + asset = tribe->GetAsset(item->GetUID()); + } + } + else + { + // Is this an asset without tribe ID? + for (size_t i=0; i<tribes.GetSize(); i++) + { + tribe = tribes[i]; + asset = tribe->GetAsset(item->GetUID()); + if (asset) break; + } + } + if (asset && tribe) + { + tribe->RemoveAsset(asset); + } + } gemNPCActor* actor = dynamic_cast<gemNPCActor*>(object); @@ -937,7 +986,7 @@ } // End Load Knowledge scope { // Start Load Assets scope - Result rs2(db->Select("select a.*,s.name AS sector_name from sc_tribe_assets a, sectors s WHERE tribe_id=%d and s.id = a.sector_id", tribe->GetID())); + Result rs2(db->Select("select a.*,s.name AS sector_name from sc_tribe_assets a LEFT JOIN sectors s on s.id = a.sector_id WHERE tribe_id=%d", tribe->GetID())); if(!rs2.IsValid()) { Error2("Could not load tribe assets from db: %s", db->GetLastError() ); Modified: trunk/src/npcclient/npcoperations.cpp =================================================================== --- trunk/src/npcclient/npcoperations.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/npcoperations.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -951,6 +951,44 @@ //--------------------------------------------------------------------------- +bool UnbuildOperation::Load(iDocumentNode *node) +{ + return true; +} + +ScriptOperation *UnbuildOperation::MakeCopy() +{ + UnbuildOperation *op = new UnbuildOperation; + return op; +} + +ScriptOperation::OperationResult UnbuildOperation::Run(NPC *npc, bool interrupted) +{ + if (npc->GetTribe()) + { + gemNPCItem* building = dynamic_cast<gemNPCItem*>(npc->GetTarget()); + if (building) + { + npc->GetTribe()->Unbuild(npc, building); + } + else + { + npc->Printf(5,"No building targeted."); + return OPERATION_FAILED; + } + + } + else + { + npc->Printf(5,"No tribe for this NPC."); + return OPERATION_FAILED; + } + + return OPERATION_COMPLETED; // Nothing more to do for this op. +} + +//--------------------------------------------------------------------------- + bool BusyOperation::Load(iDocumentNode *node) { return true; @@ -1989,6 +2027,10 @@ { return true; } + else if (split_obj[0] == "building") + { + return true; + } else if (split_obj[0] == "building_spot") { return true; @@ -2186,8 +2228,9 @@ csVector3 start_pos; psGameObject::GetPosition(npc->GetActor(),start_pos,start_rot,start_sector); - - npc->Printf(5, "LocateOp - Locate object '%s' destination '%s'", object.GetDataSafe(),destination.GetDataSafe()); + // Prepare debug of arguments + csString locateArgs; + locateArgs.AppendFmt("- Object '%s' Destination '%s'", object.GetDataSafe(), destination.GetDataSafe()); csString objectReplacedVariables = psGameObject::ReplaceNPCVariables(npc, object); csString destinationVariablesReplaced = psGameObject::ReplaceNPCVariables(npc, destination); @@ -2197,7 +2240,7 @@ if (split_obj[0] == "actor") { - npc->Printf(5,"LocateOp - Actor"); + npc->Printf(5,"LocateOp - Actor %s",locateArgs.GetDataSafe()); iSector *sector; csVector3 pos; @@ -2219,9 +2262,57 @@ located.wp = CalculateWaypoint(npc,located.pos,located.sector,-1); } + else if (split_obj[0] == "building") + { + npc->Printf(5,"LocateOp - Building %s",locateArgs.GetDataSafe()); + + if (!npc->GetTribe()) + { + return OPERATION_FAILED; + } + + Tribe::Asset* building = NULL; + + if (split_obj[1].IsEmpty()) + { + if (random) + { + building = npc->GetTribe()->GetRandomAsset(Tribe::ASSET_TYPE_BUILDING, Tribe::ASSET_STATUS_CONSTRUCTED, start_pos, start_sector, range); + } + else + { + building = npc->GetTribe()->GetNearestAsset(Tribe::ASSET_TYPE_BUILDING, Tribe::ASSET_STATUS_CONSTRUCTED, start_pos, start_sector, range); + } + } + else + { + if (random) + { + building = npc->GetTribe()->GetRandomAsset(Tribe::ASSET_TYPE_BUILDING, split_obj[1], Tribe::ASSET_STATUS_CONSTRUCTED, start_pos, start_sector, range); + } + else + { + building = npc->GetTribe()->GetNearestAsset(Tribe::ASSET_TYPE_BUILDING, split_obj[1], Tribe::ASSET_STATUS_CONSTRUCTED, start_pos, start_sector, range); + } + } + + if (building) + { + located.pos = building->pos; + located.angle = 0; + located.sector = building->sector; + located.target = building->item; + + located.wp = CalculateWaypoint(npc,located.pos,located.sector,-1); + } + else + { + return OPERATION_FAILED; + } + } else if (split_obj[0] == "building_spot") { - npc->Printf(5,"LocateOp - Building spot"); + npc->Printf(5,"LocateOp - Building spot %s",locateArgs.GetDataSafe()); Tribe::Asset* buildingSpot = npc->GetBuildingSpot(); if (buildingSpot) @@ -2244,7 +2335,7 @@ } else if (split_obj[0] == "dead") { - npc->Printf(5,"LocateOp - Dead"); + npc->Printf(5,"LocateOp - Dead %s",locateArgs.GetDataSafe()); gemNPCActor* ent = npc->GetNearestDeadActor(range); @@ -2270,7 +2361,7 @@ } else if (split_obj[0] == "entity") { - npc->Printf(5,"LocateOp - Entity"); + npc->Printf(5,"LocateOp - Entity %s",locateArgs.GetDataSafe()); gemNPCObject *entity = NULL; @@ -2309,7 +2400,7 @@ } else if(split_obj[0] == "friend") { - npc->Printf(5, "LocateOp - Friend"); + npc->Printf(5, "LocateOp - Friend %s",locateArgs.GetDataSafe()); gemNPCActor *ent = npc->GetNearestVisibleFriend(20); if(ent) @@ -2334,7 +2425,7 @@ } else if (split_obj[0] == "perception") { - npc->Printf(5,"LocateOp - Perception"); + npc->Printf(5,"LocateOp - Perception %s",locateArgs.GetDataSafe()); if (!npc->GetLastPerception()) { @@ -2352,7 +2443,7 @@ } else if (split_obj[0] == "player") { - npc->Printf(5,"LocateOp - Player"); + npc->Printf(5,"LocateOp - Player %s",locateArgs.GetDataSafe()); iSector *sector; csVector3 pos; @@ -2376,7 +2467,7 @@ } else if (split_obj[0] == "target") { - npc->Printf(5,"LocateOp - Target"); + npc->Printf(5,"LocateOp - Target %s",locateArgs.GetDataSafe()); // Since we don't have a current enemy targeted, find one! gemNPCActor* ent = npc->GetMostHated(range,locate_invisible,locate_invincible); @@ -2403,7 +2494,7 @@ } else if (split_obj[0] == "owner") { - npc->Printf(5,"LocateOp - Owner"); + npc->Printf(5,"LocateOp - Owner %s",locateArgs.GetDataSafe()); gemNPCObject *owner; // Since we don't have a current enemy targeted, find one! @@ -2432,7 +2523,7 @@ } else if (split_obj[0] == "point") { - npc->Printf(5,"LocateOp - Point"); + npc->Printf(5,"LocateOp - Point %s",locateArgs.GetDataSafe()); iSector *sector; float npc_rot; @@ -2451,7 +2542,8 @@ } else if (split_obj[0] == "region") { - npc->Printf(5,"LocateOp - Region"); + npc->Printf(5,"LocateOp - Region %s",locateArgs.GetDataSafe()); + LocationType* region = npc->GetRegion(); if (!region) { @@ -2505,7 +2597,7 @@ } else if (split_obj[0] == "self") { - npc->Printf(5,"LocateOp - Self"); + npc->Printf(5,"LocateOp - Self %s",locateArgs.GetDataSafe()); gemNPCActor *ent; @@ -2533,7 +2625,8 @@ } else if (split_obj[0] == "ownbuffer") { - npc->Printf(5, "LocateOp - Own Buffer"); + npc->Printf(5, "LocateOp - Own Buffer %s",locateArgs.GetDataSafe()); + Tribe::Memory* ownBuffer = npc->GetBufferMemory(); // If npc's buffer was never set just abandon @@ -2555,7 +2648,7 @@ } else if (split_obj[0] == "spawn") { - npc->Printf(5,"LocateOp - Spawn"); + npc->Printf(5,"LocateOp - Spawn %s",locateArgs.GetDataSafe()); located.pos = npc->GetSpawnPosition(); located.angle = 0; @@ -2565,15 +2658,17 @@ } else if (split_obj[0] == "tribe") { - npc->Printf(5,"LocateOp - Tribe"); - if (!npc->GetTribe()) { + npc->Printf(5,"LocateOp - Tribe: NO TRIBE"); + return OPERATION_FAILED; // Nothing more to do for this op. } if (split_obj[1] == "home") { + npc->Printf(5,"LocateOp - Tribe - Home %s",locateArgs.GetDataSafe()); + float radius; csVector3 pos; npc->GetTribe()->GetHome(pos,radius,located.sector); @@ -2588,6 +2683,8 @@ } else if (split_obj[1] == "memory") { + npc->Printf(5,"LocateOp - Tribe - Memory %s",locateArgs.GetDataSafe()); + float located_range=0.0; Tribe::Memory * memory; @@ -2616,13 +2713,15 @@ } else if (split_obj[1] == "resource") { + npc->Printf(5,"LocateOp - Tribe - Resource %s",locateArgs.GetDataSafe()); + npc->GetTribe()->GetResource(npc,start_pos,start_sector,located.pos,located.sector,range,random); located.angle = 0.0; located.wp = CalculateWaypoint(npc,located.pos,located.sector,-1); } else if (split_obj[0] == "target") { - npc->Printf(5,"LocateOp - Tribe Target"); + npc->Printf(5,"LocateOp - Tribe - Target %s",locateArgs.GetDataSafe()); if (!npc->GetTribe()) { @@ -2655,7 +2754,7 @@ } else if (split_obj[0] == "waypoint" ) { - npc->Printf(5, "LocateOp - Waypoint"); + npc->Printf(5, "LocateOp - Waypoint %s",locateArgs.GetDataSafe()); float located_range=0.0; @@ -2713,7 +2812,7 @@ } else if (!static_loc || !staticLocated) { - npc->Printf(5, "LocateOp - Location"); + npc->Printf(5, "LocateOp - Location %s",locateArgs.GetDataSafe()); float located_range=0.0; Location * location; @@ -3786,8 +3885,10 @@ NPC * friendNPC = npc->GetTarget()->GetNPC(); if(friendNPC) { - npc->Printf(5, "Reproduce"); - npcclient->GetNetworkMgr()->QueueSpawnCommand(friendNPC->GetActor(), npc->GetActor(), psGameObject::ReplaceNPCVariables(npc,tribeMemberType)); + csString tribeMemberTypeReplaced = psGameObject::ReplaceNPCVariables(npc,tribeMemberType); + + npc->Printf(5, "Reproduce - %s",tribeMemberTypeReplaced.GetDataSafe()); + npcclient->GetNetworkMgr()->QueueSpawnCommand(friendNPC->GetActor(), npc->GetActor(), tribeMemberTypeReplaced); } return OPERATION_COMPLETED; // Nothing more to do for this op. @@ -4259,10 +4360,36 @@ //--------------------------------------------------------------------------- +bool ProgressScriptOperation::Load(iDocumentNode *node) +{ + scriptName = node->GetAttributeValue("name"); + if (scriptName.IsEmpty()) + { + Error1("Script operation must have a name attribute"); + return false; + } + return true; +} + +ScriptOperation *ProgressScriptOperation::MakeCopy() +{ + ProgressScriptOperation *op = new ProgressScriptOperation; + op->scriptName = scriptName; + return op; +} + +ScriptOperation::OperationResult ProgressScriptOperation::Run(NPC *npc, bool interrupted) +{ + npcclient->GetNetworkMgr()->QueueScriptCommand(npc->GetActor(), npc->GetTarget(), scriptName); + return OPERATION_COMPLETED; // Nothing more to do for this op. +} + +//--------------------------------------------------------------------------- + bool SequenceOperation::Load(iDocumentNode *node) { sequenceName = node->GetAttributeValue("name"); - if (name.IsEmpty()) + if (sequenceName.IsEmpty()) { Error1("Sequence operation must have a name attribute"); return false; @@ -4314,6 +4441,64 @@ //--------------------------------------------------------------------------- +bool SetBufferOperation::Load(iDocumentNode *node) +{ + buffer = node->GetAttributeValue("buffer"); + if (buffer.IsEmpty()) + { + Error1("Set Buffer operation must have a buffer attribute"); + return false; + } + + value = node->GetAttributeValue("value"); + if (value.IsEmpty()) + { + Error1("Set Buffer operation must have a value attribute"); + return false; + } + + type = NPC_BUFFER; + + if (node->GetAttribute("type")) + { + if (csString(node->GetAttributeValue("type")).CompareNoCase("tribe")) + { + type = TRIBE_BUFFER; + } + } + + return true; +} + +ScriptOperation *SetBufferOperation::MakeCopy() +{ + SetBufferOperation *op = new SetBufferOperation; + op->buffer = buffer; + op->value = value; + op->type = type; + return op; +} + +ScriptOperation::OperationResult SetBufferOperation::Run(NPC *npc, bool interrupted) +{ + if (type == NPC_BUFFER) + { + npc->SetBuffer(buffer,value); + } + else if (type == TRIBE_BUFFER && npc->GetTribe()) + { + npc->GetTribe()->SetBuffer(buffer,value); + } + else + { + return OPERATION_FAILED; + } + + return OPERATION_COMPLETED; // Nothing more to do for this op. +} + +//--------------------------------------------------------------------------- + bool ShareMemoriesOperation::Load(iDocumentNode *node) { return true; Modified: trunk/src/npcclient/npcoperations.h =================================================================== --- trunk/src/npcclient/npcoperations.h 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/npcoperations.h 2012-08-11 20:25:53 UTC (rev 8421) @@ -353,6 +353,23 @@ //----------------------------------------------------------------------------- /** +* Will unbuild a tribe building. +*/ +class UnbuildOperation : public ScriptOperation +{ +protected: +public: + + UnbuildOperation(): ScriptOperation("Unbuild") {}; + virtual ~UnbuildOperation() {}; + virtual OperationResult Run(NPC* npc,bool interrupted); + virtual bool Load(iDocumentNode* node); + virtual ScriptOperation* MakeCopy(); +}; + +//----------------------------------------------------------------------------- + +/** * Will Set the busy indicator for an NPC. */ class BusyOperation : public ScriptOperation @@ -1201,6 +1218,32 @@ //----------------------------------------------------------------------------- +/** Script will make the progression script run at server + * + * This class is the implementation of the script operations + * used in behavior scripts for NPCS. + * + * Examples: + * <script name="my_script" /> + */ +class ProgressScriptOperation : public ScriptOperation +{ +protected: + csString scriptName; ///< The name of the script to run + + // Instance temp variables. These dosn't need to be copied. + +public: + + ProgressScriptOperation(): ScriptOperation("Script") {}; + virtual ~ProgressScriptOperation() {}; + virtual OperationResult Run(NPC* npc,bool interrupted); + virtual bool Load(iDocumentNode* node); + virtual ScriptOperation* MakeCopy(); +}; + +//----------------------------------------------------------------------------- + /** * Sequence will control a named sequence in the world. */ @@ -1231,6 +1274,33 @@ //----------------------------------------------------------------------------- /** +* SetBuffer will set a buffer for tribe or npc. +*/ +class SetBufferOperation : public ScriptOperation +{ +protected: + enum // Sequence commands, should use same values as in the psSequenceMessage + { + NPC_BUFFER = 0, + TRIBE_BUFFER = 1 + }; + + csString buffer; + csString value; + int type; + +public: + + SetBufferOperation(): ScriptOperation("SetBuffer") {}; + virtual ~SetBufferOperation() {}; + virtual OperationResult Run(NPC* npc,bool interrupted); + virtual bool Load(iDocumentNode* node); + virtual ScriptOperation* MakeCopy(); +}; + +//----------------------------------------------------------------------------- + +/** * ShareMemories will make the npc share memoreis with tribe */ class ShareMemoriesOperation : public ScriptOperation Modified: trunk/src/npcclient/recipe.cpp =================================================================== --- trunk/src/npcclient/recipe.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/recipe.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -607,8 +607,12 @@ where[1] = atoi(functionArguments.Get(1)); where[2] = atoi(functionArguments.Get(2)); iSector* sector = NULL; // Position for spots are delta values from tribe home so sector dosn't apply. - tribe->AddAsset(Tribe::ASSET_TYPE_BUILDINGSPOT, buildingName, where, sector, Tribe::ASSET_STATUS_NOT_USED); + if (!tribe->GetAsset(Tribe::ASSET_TYPE_BUILDINGSPOT, buildingName, where, sector)) + { + tribe->AddAsset(Tribe::ASSET_TYPE_BUILDINGSPOT, buildingName, where, sector, Tribe::ASSET_STATUS_NOT_USED); + } + return true; } else if(functionBody == "attack") @@ -788,12 +792,14 @@ // Check type of requirement and do something for each if(requirement.type == Recipe::REQ_TYPE_BUILDING) { - if(tribe->CheckAsset(Tribe::ASSET_TYPE_BUILDING, name, quantity)) + int count = tribe->AssetQuantity(Tribe::ASSET_TYPE_BUILDING, name); + if (count >= quantity) { - return true; + return true; // We have the required number of buildings } - for(int i=0; i<quantity; i++) + // Load receipes for each of the missing building + for(int i=0; i<(quantity-count); i++) { tribe->AddRecipe(GetRecipe(requirement.recipe), recipe); } @@ -846,12 +852,14 @@ } else if(requirement.type == Recipe::REQ_TYPE_ITEM) { - if(tribe->CheckAsset(Tribe::ASSET_TYPE_ITEM, name, quantity)) + int count = tribe->AssetQuantity(Tribe::ASSET_TYPE_ITEM, name); + if (count >= quantity) { - return true; + return true; // We have the required number of items } - for(int i=0; i<quantity; i++) + // Load receipes for each of the missing building + for(int i=0; i<(quantity-count); i++) { tribe->AddRecipe(GetRecipe(requirement.recipe), recipe); } Modified: trunk/src/npcclient/tribe.cpp =================================================================== --- trunk/src/npcclient/tribe.cpp 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/tribe.cpp 2012-08-11 20:25:53 UTC (rev 8421) @@ -837,6 +837,22 @@ } } +iSector* Tribe::Asset::GetSector() +{ + if (sector) return sector; + + if (sectorName.IsEmpty()) return NULL; + + sector = npcclient->GetEngine()->FindSector(sectorName); + return sector; +} + +gemNPCItem* Tribe::Asset::GetItem() +{ + return item; +} + + iSector* Tribe::Memory::GetSector() { if (sector) return sector; @@ -1205,36 +1221,46 @@ return false; } -bool Tribe::CheckAsset(Tribe::AssetType type, csString item, int number) +bool Tribe::CheckAsset(Tribe::AssetType type, csString name, int number) { - Asset* asset = GetAsset(type, item); - if(!asset) + for(size_t i=0; i<assets.GetSize(); i++) { - return false; - } - - // If the building exists && is not just a spot for construction - if(asset->type == Tribe::ASSET_TYPE_BUILDING) - { - if (asset->status == Tribe::ASSET_STATUS_CONSTRUCTED) + Asset* asset = assets[i]; + + if(asset->type == type && asset->name == name) { - //Requirement is met - return true; + // If the building exists && is not just a spot for construction + if(asset->type == Tribe::ASSET_TYPE_BUILDING) + { + if (asset->status == Tribe::ASSET_STATUS_CONSTRUCTED || asset->status == Tribe::ASSET_STATUS_INCONSTRUCTION) + { + number -= asset->quantity; + } + } + else if (asset->type == Tribe::ASSET_TYPE_ITEM) + { + number -= asset->quantity; + } } + if (number < 0) return true; } - else if (asset->type == Tribe::ASSET_TYPE_ITEM) + return false; +} + +size_t Tribe::AssetQuantity(Tribe::AssetType type, csString name) +{ + size_t quantity = 0; + + for(size_t i=0; i<assets.GetSize(); i++) { - if(asset->quantity > number) + Asset* asset = assets[i]; + + if(asset->type == type && asset->name == name) { - // We have enough items, requirement is met - return true; - } else - { - return false; + quantity += asset->quantity; } } - - return false; + return quantity; } void Tribe::Build(NPC* npc) @@ -1252,20 +1278,82 @@ // Now ask the server to spawn the building. Upon spawn a persit item will be sent to the client. // The new building will be added to assets as part of the HandlePersitItem prosessing. - npcclient->GetNetworkMgr()->QueueSpawnBuildingCommand(npc->GetActor(),buildingPos, buildingSector, buildingSpot->name, GetID()); + npcclient->GetNetworkMgr()->QueueSpawnBuildingCommand(npc->GetActor(), buildingPos, buildingSector, buildingSpot->name, GetID()); + + SaveAsset(buildingSpot); } } -void Tribe::HandlePersitItem(gemNPCItem* item) +void Tribe::Unbuild(NPC* npc, gemNPCItem* building) { + npc->Printf(6,"Unbuilding building %s",building->GetName()); + + Asset* buildingAsset = GetAsset(building); + if (buildingAsset) + { + buildingAsset->status = ASSET_STATUS_NOT_USED; + buildingAsset->quantity = 0; + SaveAsset(buildingAsset); + + // Check if there is a building spot that need to be downgrades as well + csVector3 buildingPos = npc->GetTribe()->GetHomePosition(); + + buildingPos -= buildingAsset->pos; + + Asset* buildingSpot = GetNearestAsset(Tribe::ASSET_TYPE_BUILDINGSPOT, buildingAsset->name, Tribe::ASSET_STATUS_CONSTRUCTED, + buildingPos, NULL, 5.0, NULL ); + if (buildingSpot) + { + buildingSpot->status = Tribe::ASSET_STATUS_NOT_USED; + SaveAsset(buildingSpot); + + // Now the building asset and the spot is freed inform the server + npcclient->GetNetworkMgr()->QueueUnbuildCommand(npc->GetActor(), building); + } + else + { + Error4("NPC %s(%s) Failed to find building spot for building %s",npc->GetName(),ShowID(npc->GetEID()),building->GetName()); + } + } + else + { + Error4("NPC %s(%s) Failed to find building asset for building %s",npc->GetName(),ShowID(npc->GetEID()),building->GetName()); + } +} + +void Tribe::HandlePersistItem(gemNPCItem* item) +{ csVector3 position; iSector* sector; psGameObject::GetPosition(item,position,sector); - - // Add the new tribe item as an asset. - // TODO: Find buildings and items and add them seperate, for now add as BUILDING. - AddAsset(Tribe::ASSET_TYPE_BUILDING, item->GetName(), position, sector, Tribe::ASSET_STATUS_CONSTRUCTED); + + // Check if we have this item as an asset + Asset* asset = GetAsset(item->GetUID()); + if (asset) + { + asset->item = item; + } + else + { + // TODO: Find buildings and items and add them seperate, for now add as BUILDING. + + asset = GetAsset(Tribe::ASSET_TYPE_BUILDING, item->GetName(), position, sector); + if (asset) + { + asset->item = item; + asset->itemUID = item->GetUID(); + SaveAsset(asset); + } + else + { + // Add the new tribe item as an asset. + asset = AddAsset(Tribe::ASSET_TYPE_BUILDING, item->GetName(), position, sector, Tribe::ASSET_STATUS_CONSTRUCTED); + asset->item = item; + asset->itemUID = item->GetUID(); + SaveAsset(asset); + } + } } @@ -1345,120 +1433,156 @@ void Tribe::LoadAsset(iResultRow &row) { - Asset asset; - asset.id = row.GetInt("id"); - asset.name = row["name"]; - asset.type = (AssetType)(row.GetInt("type")); + Asset* asset = new Asset(); + asset->id = row.GetInt("id"); + asset->name = row["name"]; + asset->type = (AssetType)(row.GetInt("type")); csVector3 coords; coords[0] = row.GetFloat("coordX"); coords[1] = row.GetFloat("coordY"); coords[2] = row.GetFloat("coordZ"); - asset.pos = coords; - asset.item = NULL; - asset.sector = npcclient->GetEngine()->GetSectors ()->FindByName(row["sector_name"]); - asset.status = (AssetStatus)(row.GetInt("status")); - asset.quantity = row.GetInt("quantity"); + asset->pos = coords; + asset->item = NULL; + asset->itemUID = row.GetInt("itemID"); + asset->sectorName = row["sector_name"]; + // Try to find the sector. Will probably fail at this point. + if (!asset->sectorName.IsEmpty()) + { + asset->sector = npcclient->GetEngine()->FindSector(asset->sectorName); + } + else + { + asset->sector = NULL; + } + asset->status = (AssetStatus)(row.GetInt("status")); + asset->quantity = row.GetInt("quantity"); assets.Push(asset); } void Tribe::SaveAsset(Tribe::Asset* asset, bool deletion) { - const char * fields[] = - {"tribe_id", "name", "type","coordX", "coordY", "coordZ", "sector_id", "gemItemName", "quantity", "status"}; - - psStringArray values; - values.FormatPush("%d",GetID()); - values.FormatPush("%s",asset->name.GetData()); - values.FormatPush("%d",asset->type); - values.FormatPush("%f",asset->pos[0]); - values.FormatPush("%f",asset->pos[1]); - values.FormatPush("%f",asset->pos[2]); - values.FormatPush("%d",asset->sector?Location::GetSectorID(db,asset->sector->QueryObject()->GetName()):-1); - values.FormatPush("%s","N/A"); // Work this out when items will be available - values.FormatPush("%d",asset->quantity); - values.FormatPush("%d",asset->status); - - if(asset->id == -1) + if (deletion) { - // It's a new entry - asset->id = db->GenericInsertWithID("sc_tribe_assets",fields,values); - if(id == 0) + if (db->Command("DELETE FROM sc_tribe_assets WHERE id=%u",asset->id)) { - CPrintf(CON_ERROR, "Failed to save asset for tribe: %s.\n", db->GetLastError()); - return; + asset->id = -1; } } else { - // Old entry updated - csString id; - id.Format("%d",asset->id); - - if(!db->GenericUpdateWithID("sc_tribe_assets","id",id,fields,values)) + const char * fields[] = + {"tribe_id", "name", "type","coordX", "coordY", "coordZ", "sector_id", "itemID", "quantity", "status"}; + + psStringArray values; + values.FormatPush("%d",GetID()); + values.FormatPush("%s",asset->name.GetData()); + values.FormatPush("%d",asset->type); + values.FormatPush("%f",asset->pos[0]); + values.FormatPush("%f",asset->pos[1]); + values.FormatPush("%f",asset->pos[2]); + values.FormatPush("%d",asset->sector?Location::GetSectorID(db,asset->sector->QueryObject()->GetName()):-1); + values.FormatPush("%d",asset->itemUID); + values.FormatPush("%d",asset->quantity); + values.FormatPush("%d",asset->status); + + if(asset->id == -1) { - CPrintf(CON_ERROR, "Failed to save asset for tribe: %s.\n", db->GetLastError()); - return; + // It's a new entry + asset->id = db->GenericInsertWithID("sc_tribe_assets",fields,values); + if(id == 0) + { + CPrintf(CON_ERROR, "Failed to save asset for tribe: %s.\n", db->GetLastError()); + return; + } } + else + { + // Old entry updated + csString id; + id.Format("%d",asset->id); + + if(!db->GenericUpdateWithID("sc_tribe_assets","id",id,fields,values)) + { + CPrintf(CON_ERROR, "Failed to save asset for tribe: %s.\n", db->GetLastError()); + return; + } + } } } + void Tribe::AddAsset(Tribe::AssetType type, csString name, gemNPCItem* item, int quantity, int id) { for(size_t i=0; i<assets.GetSize(); i++) { - if(assets[i].name == name) + if(assets[i]->name == name) { - assets[i].quantity += quantity; - SaveAsset(&assets[i]); + assets[i]->quantity += quantity; + SaveAsset(assets[i]); return; } } // No items like this before in the array - Asset asset; - asset.id = id; - asset.type = type; - asset.name = name; - asset.item = item; - asset.quantity = quantity; - asset.pos = csVector3(0,0,0); - asset.status = Tribe::ASSET_STATUS_NOT_APPLICABLE; + Asset* asset = new Asset(); + asset->id = id; + asset->type = type; + asset->name = name; + asset->item = item; + if (asset->item) + { + asset->itemUID = asset->item->GetUID(); + } + else + { + asset->itemUID = 0; + } + asset->quantity = quantity; + asset->pos = csVector3(0,0,0); + asset->status = Tribe::ASSET_STATUS_NOT_APPLICABLE; assets.Push(asset); - SaveAsset(&asset); + SaveAsset(asset); } -void Tribe::AddAsset(Tribe::AssetType type, csString name, csVector3 position, iSector* sector, Tribe::AssetStatus status) +Tribe::Asset* Tribe::AddAsset(Tribe::AssetType type, csString name, csVector3 position, iSector* sector, Tribe::AssetStatus status) { - // Just Add a new spot asset if it does not exist - if(GetAsset(type, name, position, sector)) + Asset* asset = new Asset(); + asset->id = -1; + asset->type = type; + asset->name = name; + asset->item = NULL; + asset->itemUID = 0; + asset->pos = position; + if (sector != NULL) { - // Asset already exists in the same spot. Bail - return; + asset->sectorName = sector->QueryObject()->GetName(); } + asset->sector = sector; + asset->quantity = 1; + asset->status = status; - Asset asset; - asset.id = -1; - asset.type = type; - asset.name = name; - asset.item = NULL; - asset.pos = position; - asset.sector = sector; - asset.quantity = 1; - asset.status = status; + assets.Push(asset); + SaveAsset(asset); - assets.Push(asset); - SaveAsset(&asset); - return; + return asset; } +void Tribe::RemoveAsset(Tribe::Asset* asset) +{ + SaveAsset(asset,true); // Deleation = true + assets.Delete(asset); +} + + + Tribe::Asset* Tribe::GetAsset(Tribe::AssetType type, csString name) { for(size_t i=0; i<assets.GetSize(); i++) { - if(assets[i].type == type && assets[i].name == name) + if(assets[i]->type == type && assets[i]->name == name) { - return &assets[i]; + return assets[i]; } } @@ -1470,9 +1594,9 @@ { for(size_t i=0; i<assets.GetSize(); i++) { - if(assets[i].type == type && assets[i].name == name && assets[i].status == status) + if(assets[i]->type == type && assets[i]->name == name && assets[i]->status == status) { - return &assets[i]; + return assets[i]; } } @@ -1484,29 +1608,165 @@ { for(size_t i=0; i<assets.GetSize(); i++) { - if(assets[i].type == type && assets[i].name == name && assets[i].pos == where && assets[i].sector == sector) + if(assets[i]->type == type && assets[i]->name == name && assets[i]->pos == where && assets[i]->GetSector() == sector) { - return &assets[i]; + return assets[i]; } } return NULL; } +Tribe::Asset* Tribe::GetAsset(gemNPCItem* item) +{ + for(size_t i=0; i<assets.GetSize(); i++) + { + if(assets[i]->item == item) + { + return assets[i]; + } + } + + return NULL; +} + +Tribe::Asset* Tribe::GetAsset(uint32_t itemUID) +{ + for(size_t i=0; i<assets.GetSize(); i++) + { + if(assets[i]->itemUID == itemUID) + { + return assets[i]; + } + } + + return NULL; +} + + + +Tribe::Asset* Tribe::GetRandomAsset(Tribe::AssetType type, Tribe::AssetStatus status, csVector3 pos, iSector* sector, float range) +{ + csArray<Tribe::Asset*> nearby; + + for(size_t i=0; i<assets.GetSize(); i++) + { + if(assets[i]->type == type && assets[i]->status == status) + { + float dist = npcclient->GetWorld()->Distance(pos,sector,assets[i]->pos,assets[i]->GetSector()); + + if (range < 0 || dist < range) + { + nearby.Push(assets[i]); + } + } + } + + if (nearby.GetSize()>0) // found one or more closer than range + { + size_t pick = psGetRandom((uint32)nearby.GetSize()); + + return nearby[pick]; + } + + // If we get here, the asset does not exist and we return a null one + return NULL; +} + +Tribe::Asset* Tribe::GetNearestAsset(Tribe::AssetType type, Tribe::AssetStatus status, csVector3 pos, iSector* sector, float range, float* locatedRange) +{ + Tribe::Asset* nearest = NULL; + + for(size_t i=0; i<assets.GetSize(); i++) + { + if(assets[i]->type == type && assets[i]->status == status) + { + float dist = npcclient->GetWorld()->Distance(pos,sector,assets[i]->pos,assets[i]->GetSector()); + + if (range < 0 || dist < range) + { + nearest = assets[i]; + range = dist; + } + } + } + + if (locatedRange) *locatedRange = range; + + return nearest; +} + +Tribe::Asset* Tribe::GetRandomAsset(Tribe::AssetType type, csString name, Tribe::AssetStatus status, csVector3 pos, iSector* sector, float range) +{ + csArray<Tribe::Asset*> nearby; + + for(size_t i=0; i<assets.GetSize(); i++) + { + if(assets[i]->type == type && assets[i]->name == name && assets[i]->status == status) + { + float dist = npcclient->GetWorld()->Distance(pos,sector,assets[i]->pos,assets[i]->GetSector()); + + if (range < 0 || dist < range) + { + nearby.Push(assets[i]); + } + } + } + + if (nearby.GetSize()>0) // found one or more closer than range + { + size_t pick = psGetRandom((uint32)nearby.GetSize()); + + return nearby[pick]; + } + + // If we get here, the asset does not exist and we return a null one + return NULL; +} + + +Tribe::Asset* Tribe::GetNearestAsset(Tribe::AssetType type, csString name, Tribe::AssetStatus status, csVector3 pos, iSector* sector, float range, float* locatedRange) +{ + Tribe::Asset* nearest = NULL; + + for(size_t i=0; i<assets.GetSize(); i++) + { + if(assets[i]->type == type && assets[i]->name == name && assets[i]->status == status) + { + float dist = npcclient->GetWorld()->Distance(pos,sector,assets[i]->pos,assets[i]->GetSector()); + + if (range < 0 || dist < range) + { + nearest = assets[i]; + range = dist; + } + } + } + + if (locatedRange) *locatedRange = range; + + return nearest; +} + + void Tribe::DeleteAsset(csString name, int quantity) { for(size_t i=0; i<assets.GetSize(); i++) { - if(assets[i].name == name) + if(assets[i]->name == name) { - assets[i].quantity -= quantity; + assets[i]->quantity -= quantity; // Remove entry if nothing remains - if(assets[i].quantity <= 0) + if(assets[i]->quantity <= 0) { + // Call SaveAsset with deletion = true to delete the asset + SaveAsset(assets[i], true); + assets.DeleteIndex(i); return; } - SaveAsset(&assets[i]); + // Asset not deleted so update db + SaveAsset(assets[i]); return; } } @@ -1516,7 +1776,7 @@ { for(size_t i=0; i<assets.GetSize(); i++) { - if(assets[i].name == name && assets[i].pos == pos) + if(assets[i]->name == name && assets[i]->pos == pos) { assets.DeleteIndex(i); return; @@ -1534,17 +1794,18 @@ return; } - CPrintf(CON_CMDOUTPUT, "%-15s %-25s %-6s %-25s %-15s\n", - "Name", "Type","Quant", "Position", "Status"); + CPrintf(CON_CMDOUTPUT, "%-15s %-25s %-6s %-25s %-15s %s\n", + "Name", "Type","Quant", "Position", "Status", "Item"); for(size_t i=0; i<assets.GetSize(); i++) { - CPrintf(CON_CMDOUTPUT, "%-15s %-25s %-6d %-25s %-15s\n", - assets[i].name.GetData(), - AssetTypeStr[assets[i].type], - assets[i].quantity, - toString(assets[i].pos,assets[i].sector).GetDataSafe(), - AssetStatusStr[assets[i].status]); + CPrintf(CON_CMDOUTPUT, "%-15s %-25s %-6d %-25s %-15s %s\n", + assets[i]->name.GetData(), + AssetTypeStr[assets[i]->type], + assets[i]->quantity, + toString(assets[i]->pos,assets[i]->GetSector()).GetDataSafe(), + AssetStatusStr[assets[i]->status], + assets[i]->item.IsValid()?assets[i]->item->GetName():"(NONE)"); } } Modified: trunk/src/npcclient/tribe.h =================================================================== --- trunk/src/npcclient/tribe.h 2012-08-09 16:16:19 UTC (rev 8420) +++ trunk/src/npcclient/tribe.h 2012-08-11 20:25:53 UTC (rev 8421) @@ -25,6 +25,8 @@ #include <csutil/array.h> #include <csutil/list.h> #include <csutil/priorityqueue.h> +#include <csutil/weakref.h> +#include <csutil/parray.h> #include <csgeom/vector3.h> #include <iengine/sector.h> @@ -87,16 +89,21 @@ struct Asset { - int id; - AssetType type; ///< Type of this asset. - csString name; ///< Name. Especially used for buildings - gemNPCItem* item; ///< Item representing the asset - int quantity; ///< Quantity of items of this type - csVector3 pos; ///< Position // Used only for reservations - iSector* sector; ///< The Sector - AssetStatus status; ///< Status of this asset. Used for buildings. + int id; + AssetType type; ///< Type of this asset. + csString name; ///< Name. Especially used for buildings + uint32_t itemUID; ///< The UID of the item, 0 if no item + csWeakRef<gemNPCItem> item; ///< Item representing the asset + int quantity; ///< Quantity of items of this type + csVector3 pos; ///< Position // Used only for reservations + csString sectorName;///< Name of the sector. + iSector* sector; ///< The Sector + AssetStatus status; ///< Status of this asset. Used for buildings. void Save(); + /** Get the sector */ + iSector* GetSector(); + gemNPCItem* GetItem(); }; struct Memory @@ -470,14 +477,20 @@ bool CheckResource(csString resource, int number); /** Check to see if enough assets are available */ - bool CheckAsset(Tribe::AssetType type, csString items, int number); + bool CheckAsset(Tribe::AssetType type, csString name, int number); + + /** Return the quanitity of the given asset type matching the name */ + size_t AssetQuantity(Tribe::AssetType type, csString name); /** Build a building on the current NPC building spot */ void Build(NPC* npc); - /** Handle percist items that should be assets. */ - void HandlePersitItem(gemNPCItem* item); + /** Tear down a building */ + void Unbuild(NPC* npc, gemNPCItem* building); + /** Handle persist items that should be assets. */ + void HandlePersistItem(gemNPCItem* item); + /** Returns pointers to required npcs for a task */ csArray<NPC*> SelectNPCs(const csString& type, const char* number); @@ -514,8 +527,11 @@ void AddAss... [truncated message content] |