#include "munga.h" #pragma hdrstop #include "dropzone.h" #include "random.h" #include "app.h" #include "hostmgr.h" #include "nttmgr.h" #include "notation.h" #include "namelist.h" #include "player.h" #define DOWN_TIME 5.0f //############################################################################# //############################### DropZone ################################# //############################################################################# //############################################################################# // Shared Data Support // Derivation* DropZone::GetClassDerivations() { static Derivation classDerivations(Entity::GetClassDerivations(),"DropZone"); return &classDerivations; } DropZone::SharedData DropZone::DefaultData( DropZone::GetClassDerivations(), DropZone::GetMessageHandlers(), DropZone::GetAttributeIndex(), DropZone::StateCount, (Entity::MakeHandler)DropZone::Make ); //############################################################################# // Message Support // const Receiver::HandlerEntry DropZone::MessageHandlerEntries[]= { MESSAGE_ENTRY(DropZone, AssignDropZone) }; Receiver::MessageHandlerSet& DropZone::GetMessageHandlers() { static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(DropZone::MessageHandlerEntries), DropZone::MessageHandlerEntries, Entity::GetMessageHandlers()); return messageHandlers; } //############################################################################# // Construction and Destruction // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DropZone::DropZone( DropZone::MakeMessage *creation_message, DropZone::SharedData &virtual_data ): Entity(creation_message, virtual_data) { Check_Pointer(this); Check_Pointer(creation_message); SetValidFlag(); dropZoneCount = 0; dropZones = NULL; // //-------------------------------------------------------------- // Name the drop zone, and enter the zone in the drop zone group //-------------------------------------------------------------- // Str_Copy(dropZoneName, creation_message->dropZoneName, sizeof(dropZoneName)); EntityManager *entity_manager = application->GetEntityManager(); Check(entity_manager); EntityGroup* drop_zones = entity_manager->UseGroup("DropZones"); Check(drop_zones); drop_zones->Add(this); // //----------------------------------------------------------------------- // Now, interpret the data to create the appropriate number of drop zones //----------------------------------------------------------------------- // MemoryStream stream( creation_message, creation_message->messageLength, sizeof(*creation_message) ); dropZoneCount = creation_message->dropZoneCount; Verify(dropZoneCount > 0); dropZones = new Origin[dropZoneCount]; Register_Pointer(dropZones); lastUsageTime = new Time[dropZoneCount]; Register_Pointer(lastUsageTime); lastUsedBy = new EntityID[dropZoneCount]; Register_Pointer(lastUsedBy); lastDeathCount = new int[dropZoneCount]; Register_Pointer(lastDeathCount); for (int i=0; i= 0 && index < dropZoneCount); Check(application); return !lastUsageTime[index].ticks || Now() - lastUsageTime[index] > DOWN_TIME && application->GetApplicationState() == Application::RunningMission; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DropZone::AssignDropZoneMessageHandler(AssignDropZoneMessage* message) { Check(this); Check_Pointer(message); Check(application); HostManager *host = application->GetHostManager(); Check(host); Entity *entity = host->GetEntityPointer(message->requestingEntity); Check(entity); // //--------------------------------------------------------------------- // If we have allocated a dropzone within the last ten seconds for this // player, resend the data //--------------------------------------------------------------------- // Origin *drop_zone = NULL; int lowest, highest, remaining, i; for (i=0; irequestingEntity && lastDeathCount[i] == message->deathCount ) { lastUsageTime[i] = Now(); drop_zone = &dropZones[i]; goto Found_One; } } // //------------------------------------------------------------------------ // Figure out how many drop zones are available. If none are, repost this // message to ourself //------------------------------------------------------------------------ // lowest = dropZoneCount; highest = -1; remaining = 0; for (i=0; i highest) { highest = i; } } } // //----------------------------------------------------- // Now, randomly look about until we find one available //----------------------------------------------------- // highest = highest - lowest + 1; while (remaining) { i = lowest + Random(highest); Verify(i < dropZoneCount && i >= 0); if (IsAvailable(i)) { // //------------------------------------------------------------------- // Check to see if vehicle attached to a player is within 2 meters of // this drop zone. If so, mark it unavailable for 3 seconds //------------------------------------------------------------------- // EntityManager *entity_mgr = application->GetEntityManager(); Check(entity_mgr); EntityGroup *player_group = entity_mgr->FindGroup("Players"); if ( player_group && application->GetApplicationState() == Application::RunningMission ) { Player *player; ChainIteratorOf iterator(player_group->groupMembers); while ((player = (Player*)iterator.ReadAndNext()) != NULL) { Check(player); Entity *vehicle = player->GetPlayerVehicle(); if (vehicle && player != entity) { Check(vehicle); Vector3D distance; distance.Subtract( vehicle->localOrigin.linearPosition, dropZones[i].linearPosition ); if (distance.LengthSquared() <= 4.0f) { lastUsedBy[i] = NULL; lastUsageTime[i] = Now(); lastUsageTime[i] -= DOWN_TIME - 1.0f; --remaining; if (i == lowest) { ++lowest; --highest; } else if (i == lowest + highest - 1) { --highest; } break; } } } // //---------------------------------------------------------- // If someone was in this spot, keep looking for another one //---------------------------------------------------------- // if (player) { continue; } } lastUsageTime[i] = Now(); drop_zone = &dropZones[i]; lastUsedBy[i] = message->requestingEntity; lastDeathCount[i] = message->deathCount; remaining = 0; } } // //---------------------------------------------------------------- // If no drop_zone could be found, repost the message to ourselves //---------------------------------------------------------------- // if (!drop_zone) { Time when=Now(); when += 0.1f; application->Post(MaxEventPriority, this, message, when); return; } // //-------------------------------------------------------------------- // Send a message back to the requesting object what sent this message //-------------------------------------------------------------------- // Found_One: ReplyMessage reply( message->replyMessageID, sizeof(ReplyMessage), *drop_zone, message->deathCount ); entity->Dispatch(&reply); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical DropZone::CreateMakeMessage( MakeMessage *creation_message, const char* model_name, const char* resource_name, NotationFile *map_file ) { Check(creation_message); Check(map_file); Check_Pointer(model_name); Check_Pointer(resource_name); if (!Entity::CreateMakeMessage(creation_message, map_file, NULL)) { return False; } creation_message->classToCreate = RegisteredClass::DropZoneClassID; creation_message->instanceFlags = MapFlag|TrappedFlag; // //----------------------------------------------- // Count up the number of drop zones in our model //----------------------------------------------- // Enumeration save_modes = map_file->GetModes(); map_file->SetMode(NotationFile::CleanListMode); NameList *zone_list = map_file->MakeEntryList(model_name, "dropzone"); Register_Object(zone_list); creation_message->dropZoneCount = zone_list->EntryCount(); creation_message->messageLength = sizeof(*creation_message) + creation_message->dropZoneCount*sizeof(Origin); if (!creation_message->dropZoneCount) { std::cout << "Error: " << model_name << " hasn't specified any drop zones!\n"; Dump_And_Die: Unregister_Object(zone_list); delete zone_list; map_file->PutModes(save_modes); return False; } // //--------------------------------------------- // Allocate a buffer to hold the drop zone data //--------------------------------------------- // MemoryStream stream( creation_message, creation_message->messageLength, sizeof(*creation_message) ); // //---------------------------- // zero out the drop zone name //---------------------------- // for (int ii=0; iidropZoneName); ii++) { creation_message->dropZoneName[ii] = '\0'; } Str_Copy( creation_message->dropZoneName, resource_name, sizeof(creation_message->dropZoneName) ); // //----------------- // Read in the data //----------------- // NameList::Entry *drop_zone = zone_list->GetFirstEntry(); while (drop_zone) { Point3D translation; EulerAngles tmp_rotation; const char* zone_data = drop_zone->GetChar(); sscanf( zone_data, "%f %f %f %f %f %f", &translation.x, &translation.y, &translation.z, &tmp_rotation.pitch, &tmp_rotation.yaw, &tmp_rotation.roll ); ((Origin*)stream.GetPointer())->linearPosition = translation; ((Origin*)stream.GetPointer())->angularPosition = tmp_rotation; stream.AdvancePointer(sizeof(Origin)); drop_zone = drop_zone->GetNextEntry(); } Unregister_Object(zone_list); delete zone_list; map_file->PutModes(save_modes); return True; } Logical DropZone::TestInstance() const { return IsDerivedFrom(*GetClassDerivations()); }