void TankPlayerReplicaComponent::preUpdate( float delta ) 	{
		// preUpdate will always be called once per frame

		SLBaseClass::preUpdate(delta);

		// pass over the controller values to a controller object
		_player.accessController()->setActionValue(EControllerAction_Yaw, _ctrlValues._leftRight);
		_player.accessController()->setActionValue(EControllerAction_Move, _ctrlValues._forwardBackward);
		_player.accessController()->setActionValue(EControllerAction_Shoot, _ctrlValues._shoot);		
		

		// TODO @student : the tank replica component property on the client is null
		//                 you can replicate the played replica networkid (which is done anyways already)
		//                 find the replica on the client side and let the client play
		//                 but be careful the tank might get shot ...

		if (getTopology()==CLIENT)
		{
			// this is actually client code
			// hint: you need validity checks here
			// hint: replicaManager->getReplicaByNetworkID(_ctrlValues._controlledReplicaNetworkId)

			/*
			... insert missing code
			*/
			// once you've got here the player needs to play
			if(getTankReplicaComponent() != nullptr)
			{
				if(getTankReplicaComponent()->getActorSprite() != nullptr)
				{
					AbstractVehicle* vehicle(getTankReplicaComponent()->getActorSprite()->getVehicle());
					if(vehicle != nullptr)	{
						_player.play(vehicle);
						_ctrlValues._updateTick = vehicle->updateTicks();
						
					}
				}
			}
		}
		else if (getTopology()==SERVER)
		{
			// once you've got here the player needs to play
			if(getTankReplicaComponent() != nullptr)
			{
				if(getTankReplicaComponent()->getActorSprite() != nullptr)
				{
					AbstractVehicle* vehicle(getTankReplicaComponent()->getActorSprite()->getVehicle());
					if(vehicle != nullptr)	{
						
						_player.play(vehicle);
						_ctrlValues._updateTick = vehicle->updateTicks();
						
					}
				}
			}
		}

	}
int main() {
	
	srand(time(0));
	//let user specify parameters
	printf("Specify the probability of a truck arriving, as a percentage: ");
	scanf("%d", &probabiltyOfTruckArriving);
	
	printf("Specify the max time interval between two vehicle arrivals, in milliseconds: ");
	scanf("%d", &maxTimeBetweenArrivals);
	
	initialize();
	
	//create the vehicle
	int pid = fork();
	
	if(pid == 0) {
		
		//child, its vehicle
		vehicle();
		return 0;
	}
	
	vehicleProcessId = pid;
	captain();

	terminate();
	
	return 0;
}
Car VehicleFactory::returnCar(size_t dir){
	TurnPattern::TurnPatternData tmp = turnPattern.returnPattern(dir, "car");
	Car vehicle(tmp._pTurnFunction, dir, tmp._time);

	return vehicle;

};
示例#4
0
void vehicles::on_gamemode_init(AMX* amx, samp::server_ver ver) {
    BOOST_FOREACH(pos_vehicle const& vehicle_static, vehicles_static) {
        vehicle_t vehicle(*this, vehicle_static);
        if (vehicle.create_static()) {
            vehicles_state.insert(std::make_pair(vehicle.get_id(), vehicle));
        }
    }
示例#5
0
int vehicles::vehicle_create(pos_vehicle const& pos) {
    vehicle_t vehicle(*this, pos);
    if (vehicle.create()) {
        vehicles_state.insert(std::make_pair(vehicle.get_id(), vehicle));
    }
    return vehicle.get_id();

    /*
    samp::api::ptr api_ptr = samp::api::instance();
    vehicle_t state(pos.color1, pos.color2);
    if (state.is_need_change_color()) {
        // Пытаемся найти цвета - если нашли, то ставим наш
        vehicle_defs_t::const_iterator local_def_it = vehicle_defs.find(pos.model_id);
        if (vehicle_defs.end() != local_def_it && !local_def_it->second.color_items.empty()) {
            vehicle_def_t::color_item_t const& color_item = local_def_it->second.color_items[std::rand() % local_def_it->second.color_items.size()];
            if (vehicle_t::any_color == state.color1) state.color1 = color_item.color1;
            if (vehicle_t::any_color == state.color2) state.color2 = color_item.color2;
        }
    }
    int vehicle_id = api_ptr->create_vehicle(pos.model_id, pos.x, pos.y, pos.z, pos.rz, state.color1, state.color2, pos.respawn_delay);
    api_ptr->link_vehicle_to_interior(vehicle_id, pos.interior);
    api_ptr->set_vehicle_virtualworld(vehicle_id, pos.world);
    vehicles_state.insert(std::make_pair(vehicle_id, state));
    
    if (!is_first_player_connected) {
        api_ptr->set_vehicle_to_respawn(vehicle_id);
    }
    return vehicle_id;
    */
}
cell AMX_NATIVE_CALL Natives::CreateDynamicVehicle(AMX *amx, cell *params)
{
	CHECK_PARAMS(12, "CreateDynamicVehicle");
	if (core->getData()->getGlobalMaxItems(STREAMER_TYPE_VEHICLE) == core->getData()->vehicles.size())
	{
		return 0;
	}
	int vehicleID = Item::Vehicle::identifier.get();
	Item::SharedVehicle vehicle(new Item::Vehicle);
	vehicle->amx = amx;
	vehicle->vehicleID = vehicleID;
	vehicle->modelID = static_cast<int>(params[1]);

	vehicle->spawn.position = Eigen::Vector3f(amx_ctof(params[2]), amx_ctof(params[3]), amx_ctof(params[4]));
	vehicle->spawn.angle = amx_ctof(params[5]);
	vehicle->spawn.color1 = static_cast<int>(params[6]);
	vehicle->spawn.color2 = static_cast<int>(params[7]);
	vehicle->respawnDelay = static_cast<int>(params[8]) != -1 ? static_cast<int>(params[8]) * 1000 : -1;
	vehicle->spawn.addsiren = static_cast<int>(params[9]) != 0;
	vehicle->position = vehicle->spawn.position;
	vehicle->angle = vehicle->spawn.angle;
	vehicle->color1 = vehicle->spawn.color1;
	vehicle->color2 = vehicle->spawn.color2;
	vehicle->paintjob = 4; // In GTA, you can use 0 - 3 IDs for paintjobs, 4 is invalid
	vehicle->health = 1000.0f;
	vehicle->carmods.clear();
	vehicle->touched = false;
	vehicle->used = false;
	vehicle->spawnedTick = GetTickCount();
	
	// Reset vehicle damage
	vehicle->panels = 0;
	vehicle->doors = 0;
	vehicle->lights = 0;
	vehicle->tires = 0;

	// Set vehicle parameters as unset
	vehicle->params.engine = VEHICLE_PARAMS_UNSET;
	vehicle->params.lights = VEHICLE_PARAMS_UNSET;
	vehicle->params.alarm = VEHICLE_PARAMS_UNSET;
	vehicle->params.doors = VEHICLE_PARAMS_UNSET;
	vehicle->params.bonnet = VEHICLE_PARAMS_UNSET;
	vehicle->params.boot = VEHICLE_PARAMS_UNSET;
	vehicle->params.objective = VEHICLE_PARAMS_UNSET;
	vehicle->params.siren = VEHICLE_PARAMS_UNSET;
	vehicle->params.cardoors.driver = VEHICLE_PARAMS_UNSET;
	vehicle->params.cardoors.passenger = VEHICLE_PARAMS_UNSET;
	vehicle->params.cardoors.backleft = VEHICLE_PARAMS_UNSET;
	vehicle->params.cardoors.backright = VEHICLE_PARAMS_UNSET;
	vehicle->params.carwindows.driver = VEHICLE_PARAMS_UNSET;
	vehicle->params.carwindows.passenger = VEHICLE_PARAMS_UNSET;
	vehicle->params.carwindows.backleft = VEHICLE_PARAMS_UNSET;
	vehicle->params.carwindows.backright = VEHICLE_PARAMS_UNSET;
	vehicle->worldID = static_cast<int>(params[10]);
	vehicle->interior = static_cast<int>(params[11]);
	vehicle->streamDistance = amx_ctof(params[12]) * amx_ctof(params[12]);
	core->getGrid()->addVehicle(vehicle);
	core->getData()->vehicles.insert(std::make_pair(vehicleID, vehicle));
	return static_cast<cell>(vehicleID);
}
Ambulance VehicleFactory::returnAmbulance(size_t dir){
	TurnPattern::TurnPatternData tmp = turnPattern.returnPattern(dir, "ambulance");
	Ambulance vehicle(tmp._pTurnFunction, dir, tmp._time);

	return vehicle;

};
Bike VehicleFactory::returnBike(size_t dir){
	TurnPattern::TurnPatternData tmp = turnPattern.returnPattern(dir, "bike");
	Bike vehicle(tmp._pTurnFunction, dir, tmp._time);

	return vehicle;

};
示例#9
0
Vehicle randomVehicle(double distance, double width, const Direction& d, double vRange) {
    srand((int)time(0));
	double x = random((int)width) - (width / 2);
	double y = 0 + distance;
	double z = ANTENNA_HEIGHT;
	Point p(x, y, z);
	double v = random((int)vRange);
	Vehicle vehicle(p, d, v);
	return vehicle;
}
	// server / authority code
	void DynamicActorReplicaComponent::serializeConstruction(RakNet::BitStream *constructionBitstream)	{
		CCDictionary* constructionDictionary(getConstructionDictionary());
		if(constructionDictionary != nullptr)	{
			// the vehicle position and orientation might have changed
			// so we need to perform an update here
			AbstractVehicle* vehicle(getActorSprite()->getVehicle());
			if(vehicle != nullptr)	{
				// TODO @student : modify the construction dictionary to spawn at the right place, with the right direction and right initial velocities
				
			}
			CCString* constructionJSON = CCJSONConverter::strFrom(constructionDictionary);
			constructionBitstream->Write(constructionJSON->getCString());

			getReplica()->getPeer()->log(ELogType_Info, "%s - Dictionary", constructionJSON->getCString());	

		}
	}
	void DynamicActorReplicaComponent::postUpdate( float delta ) 
	{
		// server / authority code

		if(getTopology() == SERVER)
		{
			// this boolean is dependent from the replication frequency
			if(_sampleVehicleState)
			{
				if(getActorSprite() == nullptr)
				{
					return;
				}
				// TODO @student : the vehicle has a function updateTicks
				//                 you could add this to the datagram ...
				// TODO @student : compressed datagram
				// TODO @student : extended datagram
				AbstractVehicle* vehicle(getActorSprite()->getVehicle());
				if(vehicle != nullptr)
				{
					_localSpaceData = vehicle->getLocalSpaceData();
					_motionState.readLocalSpaceData(_localSpaceData);

					_actorDatagram._x = _localSpaceData._position.x;
					_actorDatagram._y = _localSpaceData._position.y;

					_actorDatagram._fx = _localSpaceData._forward.x;
					_actorDatagram._fy = _localSpaceData._forward.y;

					_actorDatagram._lvx = _localSpaceData._linearVelocity.x;
					_actorDatagram._lvy = _localSpaceData._linearVelocity.y;
					
					_actorDatagram._killCount = _killCount; //set the current kill-count

					_actorDatagram._avz = _localSpaceData._angularVelocity.z;
				}
				_sampleVehicleState = false;
			}
		}

		SLBaseClass::postUpdate(delta);
	}
示例#12
0
int main(){

// Initializations.
	msg_t buffer;
	int len = sizeof(msg_t) - sizeof(long);

	int truck_prob = 50;
	int spawn_interval = 300;
	int ferry_travel = 500;

	printf("Enter a probability within [0..100] that a truck arrives in place of a car: ");
	scanf("%d", &truck_prob);
	printf("\nEnter the maximum time interval in milleseconds between vehicle arrivals: ");
	scanf("%d", &spawn_interval);
	printf("\nEnter the Ferry travel time in milleseconds : ");
	scanf("%d", &ferry_travel);

	key_t key_arrivals;
	key_arrivals = ftok(".","arr");
	int q_arrivals = msgget(key_arrivals, IPC_CREAT | 0660);
	printf("Arrival queue   : %d\n", q_arrivals);

	key_t key_early;
	key_early = ftok(".","ear");
	int q_early = msgget(key_early, IPC_CREAT | 0660);
	printf("Early queue     : %d\n", q_early);

	key_t key_late;
	key_late = ftok(".","lat");
	int q_late = msgget(key_late, IPC_CREAT | 0660);
	printf("Late queue      : %d\n", q_late);

	key_t key_ferry;
	key_ferry = ftok(".","fer");
	int q_ferry = msgget(key_ferry, IPC_CREAT | 0660);
	printf("Ferry deck      : %d\n", q_ferry);

	key_t key_boarded;
	key_boarded = ftok(".","boa");
	int q_boarded = msgget(key_boarded, IPC_CREAT | 0660);
	printf("Boarded vehicles: %d\n", q_boarded);

	pid_t capt;
// Spawn captain process to manage the ferry.
	if( (capt = fork()) == 0 ) captain( ferry_travel+1, q_arrivals, q_early, q_late, q_ferry, q_boarded, len );
// End Initializations.

// Keep track of children that captain did not terminate.
	int n = 1000;
	pid_t* childArray = malloc(n*sizeof(pid_t));
	pid_t child;
	int child_counter = 0;

// Start vehicle spawning until ferry loads are done.
	int timeGap;
	while( !waitpid(capt, NULL, WNOHANG) ){
		timeGap = (rand()%spawn_interval) + 1;
		usleep(timeGap*1000);
		if( (child = fork()) == 0 ){
			vehicle(truck_prob, q_arrivals, q_boarded, len);
		}else{
			childArray[child_counter] = child;
		};
		child_counter++;
		if( child_counter == n ){
			n = n*2;
			childArray = realloc(childArray, n*sizeof(pid_t));
		};
	};

// Remove all child processes.
	int v = 0;
	for( v; v < child_counter; v++ ){
		kill(childArray[v], SIGTERM);
	};
	free(childArray);

// Remove all queues.
	msgctl(q_arrivals, IPC_RMID, 0);
	msgctl(q_late, IPC_RMID, 0);
	msgctl(q_early, IPC_RMID, 0);
	msgctl(q_ferry, IPC_RMID, 0);
	msgctl(q_boarded, IPC_RMID, 0);

	return 0;
}
示例#13
0
//Our Service Client Function Definition
bool service_client(msl::socket& client,const std::string& message)
{
	//Create Parser
	std::istringstream istr(message);

	//Parse the Request
	std::string request;
	istr>>request;
	istr>>request;

	//Vehicle Get Check
	if(msl::starts_with(request,"/get"))
	{
		//Extract ID From String
		std::string id_string=request.substr(4,request.size()-4);

		//Vehicle JSON Object
		msl::json vehicle_json;

		//Set Number of Vehicles
		vehicle_json.set("length",vehicles.size());

		//Set Vehicles
		for(unsigned int ii=0;ii<vehicles.size();++ii)
			vehicle_json.set(msl::to_string(ii),vehicles[ii].json().str());

		//Return Vehicle JSON Object
		client<<msl::http_pack_string(vehicle_json.str(),"application/json");

		//Return True (We serviced the client)
		return true;
	}

	//Vehicle Add Check
	else if(msl::starts_with(request,"/add="))
	{
		//Extract ID From String
		std::string json_string=request.substr(5,request.size()-5);

		//Temp JSON Object
		msl::json temp(json_string);

		//Extract Data
		int temp_id=msl::to_int(temp.get("id"));
		std::string temp_radio=temp.get("radio");
		int temp_baud=msl::to_int(temp.get("baud"));

		//Check for Duplicates
		bool found=false;

		for(unsigned int ii=0;ii<vehicles.size();++ii)
		{
			if(temp_id==vehicles[ii].id||temp_radio==vehicles[ii].radio)
			{
				found=true;
				break;
			}
		}

		//Add New Vehicle
		if(!found)
			vehicles.push_back(vehicle(temp_id,temp_radio,temp_baud));
	}

	//Vehicle Remove Check
	else if(msl::starts_with(request,"/rm="))
	{
		//Extract ID From String
		std::string id_string=request.substr(4,request.size()-4);

		//Convert ID to Integer
		int id=msl::to_int(id_string);

		//Find and Remove Vehicle With Passed ID
		for(unsigned int ii=0;ii<vehicles.size();++ii)
			if(id==vehicles[ii].id)
				vehicles.erase(vehicles.begin()+ii);

		//Return True (We serviced the client)
		return true;
	}

	//Vehicle Set Check
	else if(msl::starts_with(request,"/set="))
	{
		//Extract the JSON Object String
		std::string json_object_string=request.substr(5,request.size()-5);

		//Create JSON Object
		msl::json json_object(json_object_string);

		//Extract JSON Object's Data
		int json_id=msl::to_int(json_object.get("id"));
		int json_dx=msl::to_int(json_object.get("dx"));
		int json_dy=msl::to_int(json_object.get("dy"));

		//Find Vehicle With Passed ID
		for(unsigned int ii=0;ii<vehicles.size();++ii)
		{
			//If ID is Found Update Vehicle Data
			if(json_id==vehicles[ii].id)
			{
				vehicles[ii].dx=json_dx;
				vehicles[ii].dy=json_dy;
				break;
			}
		}

		//Return True (We serviced the client)
		return true;
	}

	//Vehicle Connect Check
	else if(msl::starts_with(request,"/connect="))
	{
		//Extract ID From String
		std::string id_string=request.substr(9,request.size()-9);

		//Convert ID to Integer
		int id=msl::to_int(id_string);

		//Find and Connect Vehicle With Passed ID
		for(unsigned int ii=0;ii<vehicles.size();++ii)
			if(id==vehicles[ii].id)
				vehicles[ii].connect();

		//Return True (We serviced the client)
		return true;
	}

	//Vehicle Disconnect Check
	else if(msl::starts_with(request,"/disconnect="))
	{
		//Extract ID From String
		std::string id_string=request.substr(12,request.size()-12);

		//Convert ID to Integer
		int id=msl::to_int(id_string);

		//Find and Disconnect Vehicle With Passed ID
		for(unsigned int ii=0;ii<vehicles.size();++ii)
			if(id==vehicles[ii].id)
				vehicles[ii].disconnect();

		//Return True (We serviced the client)
		return true;
	}

	//Default Return False (We did not service the client)
	return false;
}
	// client / slave code
	void DynamicActorReplicaComponent::deserialize(RakNet::DeserializeParameters *deserializeParameters)
	{
		// a little base class magic
		SLBaseClass::deserialize(deserializeParameters);

		RakNet::BitStream& bitStream(deserializeParameters->serializationBitstream[0]);
		if (bitStream.GetNumberOfBitsUsed()==0)	{
			return;
		}

		//Old Way:
		//bitStream.ReadAlignedBytes( (unsigned char *)&_actorDatagram, sizeof(Dynamic2DActorDatagram) );
		
		Compressed_Dynamic2DActorDatagram comValues;
		bitStream.ReadAlignedBytes( (unsigned char *)&comValues, sizeof(Compressed_Dynamic2DActorDatagram) );

		_actorDatagram._x = comValues._x;
		_actorDatagram._y = comValues._y;
		_actorDatagram._fx = TCompressedFixpoint<float,char,8>::readInflate(comValues._fx, -1.0f, 1.0f );
		_actorDatagram._fy = TCompressedFixpoint<float,char,8>::readInflate(comValues._fy, -1.0f, 1.0f );
		_killCount = _actorDatagram._killCount = comValues._killCount;
		_actorDatagram._lvx = comValues._lvx;
		_actorDatagram._lvy = comValues._lvy;
		_actorDatagram._avz = comValues._avz;
		_actorDatagram._updateTick = comValues._updateTick;
		

		_killCount = _actorDatagram._killCount;

		if(getActorSprite() == nullptr)	{
			return;
		}

		AbstractVehicle* vehicle(getActorSprite()->getVehicle());
		if(vehicle != nullptr)	{

			Vec3 serverPosition(
				_actorDatagram._x,
				_actorDatagram._y,
				0.0f
				);

			Vec3 serverForward(
				_actorDatagram._fx,
				_actorDatagram._fy,
				0.0f
				);

			Vec3 serverLinearVelocity(
				_actorDatagram._lvx,
				_actorDatagram._lvy,
				0.0f
				);

			Vec3 serverAngularVelocity(
				0.0f,
				0.0f,
				_actorDatagram._avz
				);

			float linearInterpolationFactor(0.95f);

			Vec3 newPosition(ProtocolUtilities::interpolateNetVector(vehicle->position(),
				serverPosition, linearInterpolationFactor));

			Vec3 newForward(ProtocolUtilities::interpolateNetVector(vehicle->forward(),
				serverForward, linearInterpolationFactor));

			Vec3 newLinearVelocity(ProtocolUtilities::interpolateNetVector(vehicle->linearVelocity(),
				serverLinearVelocity, linearInterpolationFactor));

			Vec3 newAngularVelocity(ProtocolUtilities::interpolateNetVector(vehicle->angularVelocity(),
				serverAngularVelocity, linearInterpolationFactor));

			vehicle->setPosition(newPosition);
			vehicle->regenerateLocalSpace(newForward, 0.0f);

			vehicle->setLinearVelocity(newLinearVelocity);
			vehicle->setAngularVelocity(newAngularVelocity);

			// very important to notify the vehicle that 
			// it's internal state has been changed from the outside
			// see PhysicsVehicle::update
			vehicle->setDirty();

			_localSpaceData = vehicle->getLocalSpaceData();
			_motionState.readLocalSpaceData(_localSpaceData);
		}
	}
示例#15
0
void PhysicsEngine::RegisterObject(ModelNode *pItem){

  /*********************************************************************
   *ADDING SHAPES
   **********************************************************************/
  if (dynamic_cast<Shape*>(pItem) != NULL) {
    Shape* pNodeShape = (Shape*) pItem;

    /************************************
     *ADDING A RAYCAST VEHICLE
     ************************************/

    if(dynamic_cast<SimRaycastVehicle*>(pNodeShape)!=NULL){
      bullet_vehicle btRayVehicle( pItem, dynamics_world_.get(),
                                   vehicle_raycaster_);
      CollisionShapePtr pShape( btRayVehicle.getBulletShapePtr() );
      MotionStatePtr pMotionState( btRayVehicle.getBulletMotionStatePtr() );
      RigidBodyPtr body( btRayVehicle.getBulletBodyPtr() );
      VehiclePtr vehicle( btRayVehicle.getBulletRaycastVehicle() );
      std::shared_ptr<Vehicle_Entity> pEntity( new Vehicle_Entity );
      pEntity->m_pRigidBody = body;
      pEntity->m_pShape = pShape;
      pEntity->m_pMotionState = pMotionState;
      pEntity->m_pVehicle = vehicle;
      ray_vehicles_map_[pItem->GetName()] = pEntity;
    }

    //Box
    if (dynamic_cast<BoxShape*>( pNodeShape ) != NULL) {
      bullet_cube btBox(pItem);
      CollisionShapePtr pShape( btBox.getBulletShapePtr() );
      MotionStatePtr pMotionState( btBox.getBulletMotionStatePtr() );
      RigidBodyPtr body( btBox.getBulletBodyPtr() );
      dynamics_world_->addRigidBody( body.get() );

      //Save the object; easier deconstruction this way.
      std::shared_ptr<Entity> pEntity( new Entity );
      pEntity->m_pRigidBody = body;
      pEntity->m_pShape = pShape;
      pEntity->m_pMotionState = pMotionState;
      shapes_map_[pItem->GetName()] = pEntity;
    }

    //Cylinder
    else if (dynamic_cast<CylinderShape*>( pNodeShape ) != NULL) {
      bullet_cylinder btCylinder(pItem);
      CollisionShapePtr pShape( btCylinder.getBulletShapePtr() );
      MotionStatePtr pMotionState( btCylinder.getBulletMotionStatePtr() );
      RigidBodyPtr body( btCylinder.getBulletBodyPtr() );
      dynamics_world_->addRigidBody( body.get() );

      //Save the object; easier deconstruction this way.
      std::shared_ptr<Entity> pEntity( new Entity );
      pEntity->m_pRigidBody = body;
      pEntity->m_pShape = pShape;
      pEntity->m_pMotionState = pMotionState;
      shapes_map_[pItem->GetName()] = pEntity;
    }

    //Plane
    else if (dynamic_cast<PlaneShape*>( pNodeShape ) != NULL) {
      bullet_plane btPlane(pItem);
      CollisionShapePtr pShape( btPlane.getBulletShapePtr() );
      MotionStatePtr pMotionState( btPlane.getBulletMotionStatePtr() );
      RigidBodyPtr body( btPlane.getBulletBodyPtr() );
      dynamics_world_->addRigidBody( body.get() );

      //Save the object; easier deconstruction this way.
      std::shared_ptr<Entity> pEntity( new Entity );
      pEntity->m_pRigidBody = body;
      pEntity->m_pShape = pShape;
      pEntity->m_pMotionState = pMotionState;
      shapes_map_[pItem->GetName()] = pEntity;
    }

    //Heightmap
    else if (dynamic_cast<HeightmapShape*>( pNodeShape ) != NULL) {
      bullet_heightmap btMap(pItem);
      CollisionShapePtr pShape( btMap.getBulletShapePtr() );
      MotionStatePtr pMotionState( btMap.getBulletMotionStatePtr() );
      RigidBodyPtr body( btMap.getBulletBodyPtr() );
      dynamics_world_->addRigidBody( body.get() );

      //Save the object; easier deconstruction this way.
      std::shared_ptr<Entity> pEntity( new Entity );
      pEntity->m_pRigidBody = body;
      pEntity->m_pShape = pShape;
      pEntity->m_pMotionState = pMotionState;
      shapes_map_[pItem->GetName()] = pEntity;
    }

    //Mesh
    else if (dynamic_cast<MeshShape*>( pNodeShape ) != NULL){
      bullet_mesh btMesh(pItem);
      CollisionShapePtr pShape( btMesh.getBulletShapePtr() );
      MotionStatePtr pMotionState( btMesh.getBulletMotionStatePtr() );
      RigidBodyPtr body( btMesh.getBulletBodyPtr() );
      dynamics_world_->addRigidBody( body.get() );

      //Save the object; easier deconstruction this way.
      std::shared_ptr<Entity> pEntity( new Entity );
      pEntity->m_pRigidBody = body;
      pEntity->m_pShape = pShape;
      pEntity->m_pMotionState = pMotionState;
      shapes_map_[pItem->GetName()] = pEntity;
    }
  }



  /*********************************************************************
   *ADDING CONSTRAINTS
   **********************************************************************/

  else if (dynamic_cast<Constraint*>(pItem) != NULL) {
    Constraint* pNodeCon = (Constraint*) pItem;
    // Point to Point
    if (dynamic_cast<PToPOne*>( pNodeCon ) != NULL) {
      PToPOne* pCon = (PToPOne*) pNodeCon;
      btRigidBody* RigidShape_A;
      if(isVehicle(pCon->m_Shape_A)){
        std::shared_ptr<Vehicle_Entity> Shape_A = ray_vehicles_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_A = shapes_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      btVector3 pivot_A(pCon->m_pivot_in_A[0], pCon->m_pivot_in_A[1],
                        pCon->m_pivot_in_A[2]);
      btPoint2PointConstraint* PToP =
          new btPoint2PointConstraint(*RigidShape_A, pivot_A);
      dynamics_world_->addConstraint(PToP);
      ptop_map_[pCon->GetName()] = PToP;
    }

    else if(dynamic_cast<PToPTwo*>( pNodeCon ) != NULL) {
      PToPTwo* pCon = (PToPTwo*) pNodeCon;
      btRigidBody* RigidShape_A;
      btRigidBody* RigidShape_B;
      if(isVehicle(pCon->m_Shape_A)){
        std::shared_ptr<Vehicle_Entity> Shape_A = ray_vehicles_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_A = shapes_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      if(isVehicle(pCon->m_Shape_B)){
        std::shared_ptr<Vehicle_Entity> Shape_B = ray_vehicles_map_.at(pCon->m_Shape_B);
        RigidShape_B = Shape_B->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_B = shapes_map_.at(pCon->m_Shape_B);
        RigidShape_B = Shape_B->m_pRigidBody.get();
      }
      btVector3 pivot_A(pCon->m_pivot_in_A[0], pCon->m_pivot_in_A[1],
                        pCon->m_pivot_in_A[2]);
      btVector3 pivot_B(pCon->m_pivot_in_B[0], pCon->m_pivot_in_B[1],
                        pCon->m_pivot_in_B[2]);
      btPoint2PointConstraint* PToP =
          new btPoint2PointConstraint(*RigidShape_A, *RigidShape_B,
                                      pivot_A, pivot_B);
      dynamics_world_->addConstraint(PToP);
      ptop_map_[pCon->GetName()] = PToP;
    }

    //Hinge
    else if(dynamic_cast<HingeOnePivot*>( pNodeCon ) != NULL) {
      HingeOnePivot* pCon = (HingeOnePivot*) pNodeCon;
      btRigidBody* RigidShape_A;
      if(isVehicle(pCon->m_Shape_A)){
        std::shared_ptr<Vehicle_Entity> Shape_A = ray_vehicles_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_A = shapes_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      btVector3 pivot_A(pCon->m_pivot_in_A[0], pCon->m_pivot_in_A[1],
                        pCon->m_pivot_in_A[2]);
      btVector3 axis_A(pCon->m_axis_in_A[0], pCon->m_axis_in_A[1],
                       pCon->m_axis_in_A[2]);
      btHingeConstraint* Hinge =
          new btHingeConstraint(*RigidShape_A, pivot_A,
                                axis_A, true);
      Hinge->setLimit(pCon->m_low_limit, pCon->m_high_limit, pCon->m_softness,
                      pCon->m_bias, pCon->m_relaxation);
      dynamics_world_->addConstraint(Hinge);
      hinge_map_[pCon->GetName()] = Hinge;
    }

    else if(dynamic_cast<HingeTwoPivot*>( pNodeCon ) != NULL) {
      HingeTwoPivot* pCon = (HingeTwoPivot*) pNodeCon;
      btRigidBody* RigidShape_A;
      btRigidBody* RigidShape_B;
      if(isVehicle(pCon->m_Shape_A)){
        std::shared_ptr<Vehicle_Entity> Shape_A = ray_vehicles_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_A = shapes_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      if(isVehicle(pCon->m_Shape_B)){
        std::shared_ptr<Vehicle_Entity> Shape_B = ray_vehicles_map_.at(pCon->m_Shape_B);
        RigidShape_B = Shape_B->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_B = shapes_map_.at(pCon->m_Shape_B);
        RigidShape_B = Shape_B->m_pRigidBody.get();
      }
      btVector3 pivot_A(pCon->m_pivot_in_A[0], pCon->m_pivot_in_A[1],
                        pCon->m_pivot_in_A[2]);
      btVector3 axis_A(pCon->m_axis_in_A[0], pCon->m_axis_in_A[1],
                       pCon->m_axis_in_A[2]);
      btVector3 pivot_B(pCon->m_pivot_in_B[0], pCon->m_pivot_in_B[1],
                        pCon->m_pivot_in_B[2]);
      btVector3 axis_B(pCon->m_axis_in_B[0], pCon->m_axis_in_B[1],
                       pCon->m_axis_in_B[2]);
      btHingeConstraint* Hinge =
          new btHingeConstraint(*RigidShape_A,
                                *RigidShape_B,
                                pivot_A, pivot_B,
                                axis_A, axis_B,
                                true);
      Hinge->setLimit(pCon->m_low_limit, pCon->m_high_limit, pCon->m_softness,
                      pCon->m_bias, pCon->m_relaxation);
      dynamics_world_->addConstraint(Hinge);
      hinge_map_[pCon->GetName()] = Hinge;
    }

    //Hinge2
    else if(dynamic_cast<Hinge2*>( pNodeCon ) != NULL) {
      Hinge2* pCon = (Hinge2*) pNodeCon;
      btRigidBody* RigidShape_A;
      btRigidBody* RigidShape_B;
      if(isVehicle(pCon->m_Shape_A)){
        std::shared_ptr<Vehicle_Entity> Shape_A = ray_vehicles_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_A = shapes_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      if(isVehicle(pCon->m_Shape_B)){
        std::shared_ptr<Vehicle_Entity> Shape_B = ray_vehicles_map_.at(pCon->m_Shape_B);
        RigidShape_B = Shape_B->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_B = shapes_map_.at(pCon->m_Shape_B);
        RigidShape_B = Shape_B->m_pRigidBody.get();
      }
      btVector3 btAnchor(pCon->m_Anchor[0], pCon->m_Anchor[1],
                         pCon->m_Anchor[2]);
      btVector3 btAxis_1(pCon->m_Axis_1[0], pCon->m_Axis_1[1],
                         pCon->m_Axis_1[2]);
      btVector3 btAxis_2(pCon->m_Axis_2[0], pCon->m_Axis_2[1],
                         pCon->m_Axis_2[2]);
      btHinge2Constraint* Hinge =
          new btHinge2Constraint(*RigidShape_A, *RigidShape_B,
                                 btAnchor, btAxis_1, btAxis_2);
      Hinge->setAngularLowerLimit(toBulletVec3(pCon->m_LowerAngLimit));
      Hinge->setAngularUpperLimit(toBulletVec3(pCon->m_UpperAngLimit));
      Hinge->setLinearLowerLimit(toBulletVec3(pCon->m_LowerLinLimit));
      Hinge->setLinearUpperLimit(toBulletVec3(pCon->m_UpperLinLimit));
      Hinge->enableSpring(3, true);
      Hinge->setStiffness(3, pCon->m_stiffness);
      Hinge->setDamping(3, pCon->m_damping);
      dynamics_world_->addConstraint(Hinge);
      hinge2_map_[pCon->GetName()] = Hinge;
    }

    //SixDOF
    else if(dynamic_cast<SixDOFOne*>( pNodeCon ) != NULL) {
      SixDOFOne* pCon = (SixDOFOne*) pNodeCon;
      std::shared_ptr<Entity> Shape_A = shapes_map_.at(pCon->m_Shape_A);
      btTransform trans_A = toBullet(_Cart2T(pCon->m_Transform_A));
      btGeneric6DofConstraint* SixDOF =
          new btGeneric6DofConstraint(*Shape_A->m_pRigidBody.get(),
                                      trans_A,
                                      true);
      SixDOF->setLinearLowerLimit(toBulletVec3(pCon->m_LowerLinLimit));
      SixDOF->setLinearUpperLimit(toBulletVec3(pCon->m_UpperLinLimit));
      SixDOF->setAngularLowerLimit(toBulletVec3(pCon->m_LowerAngLimit));
      SixDOF->setAngularUpperLimit(toBulletVec3(pCon->m_UpperAngLimit));
      dynamics_world_->addConstraint(SixDOF);
      sixdof_map_[pCon->GetName()] = SixDOF;
    }

    else if(dynamic_cast<SixDOFTwo*>( pNodeCon ) != NULL) {
      SixDOFTwo* pCon = (SixDOFTwo*) pNodeCon;
      btRigidBody* RigidShape_A;
      btRigidBody* RigidShape_B;
      if(isVehicle(pCon->m_Shape_A)){
        std::shared_ptr<Vehicle_Entity> Shape_A = ray_vehicles_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_A = shapes_map_.at(pCon->m_Shape_A);
        RigidShape_A = Shape_A->m_pRigidBody.get();
      }
      if(isVehicle(pCon->m_Shape_B)){
        std::shared_ptr<Vehicle_Entity> Shape_B = ray_vehicles_map_.at(pCon->m_Shape_B);
        RigidShape_B = Shape_B->m_pRigidBody.get();
      }
      else{
        std::shared_ptr<Entity> Shape_B = shapes_map_.at(pCon->m_Shape_B);
        RigidShape_B = Shape_B->m_pRigidBody.get();
      }
      btTransform trans_A = toBullet(_Cart2T(pCon->m_Transform_A));
      btTransform trans_B = toBullet(_Cart2T(pCon->m_Transform_B));
      btGeneric6DofConstraint* SixDOF =
          new btGeneric6DofConstraint(*RigidShape_A, *RigidShape_B,
                                      trans_A, trans_B,
                                      true);
      SixDOF->setLinearLowerLimit(toBulletVec3(pCon->m_LowerLinLimit));
      SixDOF->setLinearUpperLimit(toBulletVec3(pCon->m_UpperLinLimit));
      SixDOF->setAngularLowerLimit(toBulletVec3(pCon->m_LowerAngLimit));
      SixDOF->setAngularUpperLimit(toBulletVec3(pCon->m_UpperAngLimit));
      dynamics_world_->addConstraint(SixDOF);
      sixdof_map_[pCon->GetName()] = SixDOF;
    }
  }

  return;

}
	//-----------------------------------------------------------------------------
	AbstractVehicle* Pedestrian::cloneVehicle( void ) const
	{
		AbstractVehicle* vehicle(ET_NEW Pedestrian());
		return vehicle;
	}
示例#17
0
bool game::dump_stats( const std::string &what, dump_mode mode,
                       const std::vector<std::string> &opts )
{
    try {
        loading_ui ui( false );
        load_core_data( ui );
        load_packs( _( "Loading content packs" ), { mod_id( "dda" ) }, ui );
        DynamicDataLoader::get_instance().finalize_loaded_data( ui );
    } catch( const std::exception &err ) {
        std::cerr << "Error loading data from json: " << err.what() << std::endl;
        return false;
    }

    std::vector<std::string> header;
    std::vector<std::vector<std::string>> rows;

    int scol = 0; // sorting column

    std::map<std::string, standard_npc> test_npcs;
    test_npcs[ "S1" ] = standard_npc( "S1", { "gloves_survivor", "mask_lsurvivor" }, 4, 8, 10, 8,
                                      10 /* DEX 10, PER 10 */ );
    test_npcs[ "S2" ] = standard_npc( "S2", { "gloves_fingerless", "sunglasses" }, 4, 8, 8, 8,
                                      10 /* PER 10 */ );
    test_npcs[ "S3" ] = standard_npc( "S3", { "gloves_plate", "helmet_plate" },  4, 10, 8, 8,
                                      8 /* STAT 10 */ );
    test_npcs[ "S4" ] = standard_npc( "S4", {}, 0, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S5" ] = standard_npc( "S5", {}, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S6" ] = standard_npc( "S6", { "gloves_hsurvivor", "mask_hsurvivor" }, 4, 8, 10, 8,
                                      10 /* DEX 10, PER 10 */ );

    std::map<std::string, item> test_items;
    test_items[ "G1" ] = item( "glock_19" ).ammo_set( "9mm" );
    test_items[ "G2" ] = item( "hk_mp5" ).ammo_set( "9mm" );
    test_items[ "G3" ] = item( "ar15" ).ammo_set( "223" );
    test_items[ "G4" ] = item( "remington_700" ).ammo_set( "270" );
    test_items[ "G4" ].emplace_back( "rifle_scope" );

    if( what == "AMMO" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Stack",
            "Range", "Dispersion", "Recoil", "Damage", "Pierce"
        };
        auto dump = [&rows]( const item & obj ) {
            // a common task is comparing ammo by type so ammo has multiple repeat the entry
            for( const auto &e : obj.type->ammo->type ) {
                std::vector<std::string> r;
                r.push_back( obj.tname( 1, false ) );
                r.push_back( e.str() );
                r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
                r.push_back( to_string( to_gram( obj.weight() ) ) );
                r.push_back( to_string( obj.type->stack_size ) );
                r.push_back( to_string( obj.type->ammo->range ) );
                r.push_back( to_string( obj.type->ammo->dispersion ) );
                r.push_back( to_string( obj.type->ammo->recoil ) );
                damage_instance damage = obj.type->ammo->damage;
                r.push_back( to_string( damage.total_damage() ) );
                r.push_back( to_string( damage.empty() ? 0 : ( *damage.begin() ).res_pen ) );
                rows.push_back( r );
            }
        };
        for( const itype *e : item_controller->all() ) {
            if( e->ammo ) {
                dump( item( e, calendar::turn, item::solitary_tag {} ) );
            }
        }

    } else if( what == "ARMOR" ) {
        header = {
            "Name", "Encumber (fit)", "Warmth", "Weight", "Storage", "Coverage", "Bash", "Cut", "Acid", "Fire"
        };
        auto dump = [&rows]( const item & obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( 1, false ) );
            r.push_back( to_string( obj.get_encumber() ) );
            r.push_back( to_string( obj.get_warmth() ) );
            r.push_back( to_string( to_gram( obj.weight() ) ) );
            r.push_back( to_string( obj.get_storage() / units::legacy_volume_factor ) );
            r.push_back( to_string( obj.get_coverage() ) );
            r.push_back( to_string( obj.bash_resist() ) );
            r.push_back( to_string( obj.cut_resist() ) );
            r.push_back( to_string( obj.acid_resist() ) );
            r.push_back( to_string( obj.fire_resist() ) );
            rows.push_back( r );
        };

        body_part bp = opts.empty() ? num_bp : get_body_part_token( opts.front() );

        for( const itype *e : item_controller->all() ) {
            if( e->armor ) {
                item obj( e );
                if( bp == num_bp || obj.covers( bp ) ) {
                    if( obj.has_flag( "VARSIZE" ) ) {
                        obj.item_tags.insert( "FIT" );
                    }
                    dump( obj );
                }
            }
        }

    } else if( what == "EDIBLE" ) {
        header = {
            "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy"
        };
        for( const auto &v : vitamin::all() ) {
            header.push_back( v.second.name() );
        }
        auto dump = [&rows]( const item & obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
            r.push_back( to_string( to_gram( obj.weight() ) ) );
            r.push_back( to_string( obj.type->stack_size ) );
            r.push_back( to_string( obj.type->comestible->get_calories() ) );
            r.push_back( to_string( obj.type->comestible->quench ) );
            r.push_back( to_string( obj.type->comestible->healthy ) );
            auto vits = g->u.vitamins_from( obj );
            for( const auto &v : vitamin::all() ) {
                r.push_back( to_string( vits[ v.first ] ) );
            }
            rows.push_back( r );
        };

        for( const itype *e : item_controller->all() ) {
            item food( e, calendar::turn, item::solitary_tag {} );

            if( food.is_food() && g->u.can_eat( food ).success() ) {
                dump( food );
            }
        }

    } else if( what == "GUN" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Capacity",
            "Range", "Dispersion", "Effective recoil", "Damage", "Pierce",
            "Aim time", "Effective range", "Snapshot range", "Max range"
        };

        std::set<std::string> locations;
        for( const itype *e : item_controller->all() ) {
            if( e->gun ) {
                std::transform( e->gun->valid_mod_locations.begin(),
                                e->gun->valid_mod_locations.end(),
                                std::inserter( locations, locations.begin() ),
                []( const std::pair<gunmod_location, int> &q ) {
                    return q.first.name();
                } );
            }
        }
        for( const auto &e : locations ) {
            header.push_back( e );
        }

        auto dump = [&rows, &locations]( const standard_npc & who, const item & obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( 1, false ) );
            r.push_back( obj.ammo_type() ? obj.ammo_type().str() : "" );
            r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
            r.push_back( to_string( to_gram( obj.weight() ) ) );
            r.push_back( to_string( obj.ammo_capacity() ) );
            r.push_back( to_string( obj.gun_range() ) );
            r.push_back( to_string( obj.gun_dispersion() ) );
            r.push_back( to_string( obj.gun_recoil( who ) ) );
            damage_instance damage = obj.gun_damage();
            r.push_back( to_string( damage.total_damage() ) );
            r.push_back( to_string( damage.empty() ? 0 : ( *damage.begin() ).res_pen ) );

            r.push_back( to_string( who.gun_engagement_moves( obj ) ) );

            for( const auto &e : locations ) {
                const auto &vml = obj.type->gun->valid_mod_locations;
                const auto iter = vml.find( e );
                r.push_back( to_string( iter != vml.end() ? iter->second : 0 ) );
            }
            rows.push_back( r );
        };
        for( const itype *e : item_controller->all() ) {
            if( e->gun ) {
                item gun( e );
                if( !gun.magazine_integral() ) {
                    gun.emplace_back( gun.magazine_default() );
                }
                gun.ammo_set( gun.ammo_type()->default_ammotype(), gun.ammo_capacity() );

                dump( test_npcs[ "S1" ], gun );

                if( gun.type->gun->barrel_length > 0 ) {
                    gun.emplace_back( "barrel_small" );
                    dump( test_npcs[ "S1" ], gun );
                }
            }
        }

    } else if( what == "RECIPE" ) {

        // optionally filter recipes to include only those using specified skills
        recipe_subset dict;
        for( const auto &r : recipe_dict ) {
            if( opts.empty() || std::any_of( opts.begin(), opts.end(), [&r]( const std::string & s ) {
            if( r.second.skill_used == skill_id( s ) && r.second.difficulty > 0 ) {
                    return true;
                }
                auto iter = r.second.required_skills.find( skill_id( s ) );
                return iter != r.second.required_skills.end() && iter->second > 0;
            } ) ) {
                dict.include( &r.second );
            }
        }

        // only consider skills that are required by at least one recipe
        std::vector<Skill> sk;
        std::copy_if( Skill::skills.begin(), Skill::skills.end(),
        std::back_inserter( sk ), [&dict]( const Skill & s ) {
            return std::any_of( dict.begin(), dict.end(), [&s]( const recipe * r ) {
                return r->skill_used == s.ident() ||
                       r->required_skills.find( s.ident() ) != r->required_skills.end();
            } );
        } );

        header = { "Result" };

        for( const auto &e : sk ) {
            header.push_back( e.ident().str() );
        }

        for( const recipe *e : dict ) {
            std::vector<std::string> r;
            r.push_back( e->result_name() );
            for( const auto &s : sk ) {
                if( e->skill_used == s.ident() ) {
                    r.push_back( to_string( e->difficulty ) );
                } else {
                    auto iter = e->required_skills.find( s.ident() );
                    r.push_back( to_string( iter != e->required_skills.end() ? iter->second : 0 ) );
                }
            }
            rows.push_back( r );
        }

    } else if( what == "VEHICLE" ) {
        header = {
            "Name", "Weight (empty)", "Weight (fueled)",
            "Max velocity (mph)", "Safe velocity (mph)", "Acceleration (mph/turn)",
            "Mass coeff %", "Aerodynamics coeff %", "Friction coeff %",
            "Traction coeff % (grass)"
        };
        auto dump = [&rows]( const vproto_id & obj ) {
            auto veh_empty = vehicle( obj, 0, 0 );
            auto veh_fueled = vehicle( obj, 100, 0 );

            std::vector<std::string> r;
            r.push_back( veh_empty.name );
            r.push_back( to_string( to_kilogram( veh_empty.total_mass() ) ) );
            r.push_back( to_string( to_kilogram( veh_fueled.total_mass() ) ) );
            r.push_back( to_string( veh_fueled.max_velocity() / 100 ) );
            r.push_back( to_string( veh_fueled.safe_velocity() / 100 ) );
            r.push_back( to_string( veh_fueled.acceleration() / 100 ) );
            r.push_back( to_string( ( int )( 100 * veh_fueled.k_mass() ) ) );
            r.push_back( to_string( ( int )( 100 * veh_fueled.k_aerodynamics() ) ) );
            r.push_back( to_string( ( int )( 100 * veh_fueled.k_friction() ) ) );
            r.push_back( to_string( ( int )( 100 * veh_fueled.k_traction( veh_fueled.wheel_area(
                                                 false ) / 2.0f ) ) ) );
            rows.push_back( r );
        };
        for( auto &e : vehicle_prototype::get_all() ) {
            dump( e );
        }

    } else if( what == "VPART" ) {
        header = {
            "Name", "Location", "Weight", "Size"
        };
        auto dump = [&rows]( const vpart_info & obj ) {
            std::vector<std::string> r;
            r.push_back( obj.name() );
            r.push_back( obj.location );
            r.push_back( to_string( int( ceil( to_gram( item( obj.item ).weight() ) / 1000.0 ) ) ) );
            r.push_back( to_string( obj.size / units::legacy_volume_factor ) );
            rows.push_back( r );
        };
        for( const auto &e : vpart_info::all() ) {
            dump( e.second );
        }

    } else {
        std::cerr << "unknown argument: " << what << std::endl;
        return false;
    }

    rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string> &e ) {
        return e.empty();
    } ), rows.end() );

    if( scol >= 0 ) {
        std::sort( rows.begin(), rows.end(), [&scol]( const std::vector<std::string> &lhs,
        const std::vector<std::string> &rhs ) {
            return lhs[ scol ] < rhs[ scol ];
        } );
    }

    rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() );

    switch( mode ) {
        case dump_mode::TSV:
            rows.insert( rows.begin(), header );
            for( const auto &r : rows ) {
                std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) );
                std::cout << r.back() << "\n";
            }
            break;

        case dump_mode::HTML:
            std::cout << "<table>";

            std::cout << "<thead>";
            std::cout << "<tr>";
            for( const auto &col : header ) {
                std::cout << "<th>" << col << "</th>";
            }
            std::cout << "</tr>";
            std::cout << "</thead>";

            std::cout << "<tdata>";
            for( const auto &r : rows ) {
                std::cout << "<tr>";
                for( const auto &col : r ) {
                    std::cout << "<td>" << col << "</td>";
                }
                std::cout << "</tr>";
            }
            std::cout << "</tdata>";

            std::cout << "</table>";
            break;
    }

    return true;
}
示例#18
0
bool game::dump_stats( const std::string& what, dump_mode mode, const std::vector<std::string> &opts )
{
    try {
        load_core_data();
    } catch( const std::exception &err ) {
        std::cerr << "Error loading data from json: " << err.what() << std::endl;
        return false;
    }
    DynamicDataLoader::get_instance().finalize_loaded_data();

    std::vector<std::string> header;
    std::vector<std::vector<std::string>> rows;

    int scol = 0; // sorting column

    std::map<std::string, standard_npc> test_npcs;
    test_npcs[ "S1" ] = standard_npc( "S1", { "gloves_survivor", "mask_lsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S2" ] = standard_npc( "S2", { "gloves_fingerless", "sunglasses" }, 4, 8, 8, 8, 10 /* PER 10 */ );
    test_npcs[ "S3" ] = standard_npc( "S3", { "gloves_plate", "helmet_plate" },  4, 10, 8, 8, 8 /* STAT 10 */ );
    test_npcs[ "S4" ] = standard_npc( "S4", {}, 0, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S5" ] = standard_npc( "S5", {}, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );
    test_npcs[ "S6" ] = standard_npc( "S6", { "gloves_hsurvivor", "mask_hsurvivor" }, 4, 8, 10, 8, 10 /* DEX 10, PER 10 */ );

    std::map<std::string, item> test_items;
    test_items[ "G1" ] = item( "glock_19" ).ammo_set( "9mm" );
    test_items[ "G2" ] = item( "hk_mp5" ).ammo_set( "9mm" );
    test_items[ "G3" ] = item( "ar15" ).ammo_set( "223" );
    test_items[ "G4" ] = item( "remington_700" ).ammo_set( "270" );
    test_items[ "G4" ].emplace_back( "rifle_scope" );

    if( what == "AMMO" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Stack",
            "Range", "Dispersion", "Recoil", "Damage", "Pierce"
        };
        auto dump = [&rows]( const item& obj ) {
            // a common task is comparing ammo by type so ammo has multiple repeat the entry
            for( const auto &e : obj.type->ammo->type ) {
                std::vector<std::string> r;
                r.push_back( obj.tname( 1, false ) );
                r.push_back( e.str() );
                r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
                r.push_back( to_string( obj.weight() ) );
                r.push_back( to_string( obj.type->stack_size ) );
                r.push_back( to_string( obj.type->ammo->range ) );
                r.push_back( to_string( obj.type->ammo->dispersion ) );
                r.push_back( to_string( obj.type->ammo->recoil ) );
                r.push_back( to_string( obj.type->ammo->damage ) );
                r.push_back( to_string( obj.type->ammo->pierce ) );
                rows.push_back( r );
            }
        };
        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second.ammo ) {
                dump( item( e.first, calendar::turn, item::solitary_tag {} ) );
            }
        }

    } else if( what == "ARMOR" ) {
        header = {
            "Name", "Encumber (fit)", "Warmth", "Weight", "Storage", "Coverage", "Bash", "Cut", "Acid", "Fire"
        };
        auto dump = [&rows]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( 1, false ) );
            r.push_back( to_string( obj.get_encumber() ) );
            r.push_back( to_string( obj.get_warmth() ) );
            r.push_back( to_string( obj.weight() ) );
            r.push_back( to_string( obj.get_storage() / units::legacy_volume_factor ) );
            r.push_back( to_string( obj.get_coverage() ) );
            r.push_back( to_string( obj.bash_resist() ) );
            r.push_back( to_string( obj.cut_resist() ) );
            r.push_back( to_string( obj.acid_resist() ) );
            r.push_back( to_string( obj.fire_resist() ) );
            rows.push_back( r );
        };

        body_part bp = opts.empty() ? num_bp : get_body_part_token( opts.front() );

        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second.armor ) {
                item obj( e.first );
                if( bp == num_bp || obj.covers( bp ) ) {
                    if( obj.has_flag( "VARSIZE" ) ) {
                        obj.item_tags.insert( "FIT" );
                    }
                    dump( obj );
                }
            }
        }

    } else if( what == "EDIBLE" ) {
        header = {
            "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy"
        };
        for( const auto& v : vitamin::all() ) {
             header.push_back( v.second.name() );
        }
        auto dump = [&rows,&test_npcs]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
            r.push_back( to_string( obj.weight() ) );
            r.push_back( to_string( obj.type->stack_size ) );
            r.push_back( to_string( obj.type->comestible->get_calories() ) );
            r.push_back( to_string( obj.type->comestible->quench ) );
            r.push_back( to_string( obj.type->comestible->healthy ) );
            auto vits = g->u.vitamins_from( obj );
            for( const auto& v : vitamin::all() ) {
                 r.push_back( to_string( vits[ v.first ] ) );
            }
            rows.push_back( r );
        };
        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second.comestible &&
                ( e.second.comestible->comesttype == "FOOD" ||
                  e.second.comestible->comesttype == "DRINK" ) ) {

                item food( e.first, calendar::turn, item::solitary_tag {} );
                if( g->u.can_eat( food, false, true ) == EDIBLE ) {
                    dump( food );
                }
            }
        }

    } else if( what == "GUN" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Capacity",
            "Range", "Dispersion", "Effective recoil", "Damage", "Pierce",
            "Aim time", "Effective range", "Snapshot range", "Max range"
        };

        std::set<std::string> locations;
        for( const auto& e : item_controller->get_all_itypes() ) {
            if( e.second.gun ) {
                std::transform( e.second.gun->valid_mod_locations.begin(),
                                e.second.gun->valid_mod_locations.end(),
                                std::inserter( locations, locations.begin() ),
                                []( const std::pair<std::string, int>& e ) { return e.first; } );
            }
        }
        for( const auto &e : locations ) {
            header.push_back( e );
        }

        auto dump = [&rows,&locations]( const standard_npc &who, const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( 1, false ) );
            r.push_back( obj.ammo_type() ? obj.ammo_type().str() : "" );
            r.push_back( to_string( obj.volume() / units::legacy_volume_factor ) );
            r.push_back( to_string( obj.weight() ) );
            r.push_back( to_string( obj.ammo_capacity() ) );
            r.push_back( to_string( obj.gun_range() ) );
            r.push_back( to_string( obj.gun_dispersion() ) );
            r.push_back( to_string( obj.gun_recoil( who ) ) );
            r.push_back( to_string( obj.gun_damage() ) );
            r.push_back( to_string( obj.gun_pierce() ) );

            r.push_back( to_string( who.gun_engagement_moves( obj ) ) );

            r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::effective ) ) );
            r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::snapshot ) ) );
            r.push_back( string_format( "%.1f", who.gun_engagement_range( obj, player::engagement::maximum ) ) );

            for( const auto &e : locations ) {
                r.push_back( to_string( obj.type->gun->valid_mod_locations[ e ] ) );
            }
            rows.push_back( r );
        };
        for( const auto& e : item_controller->get_all_itypes() ) {
            if( e.second.gun ) {
                item gun( e.first );
                if( !gun.magazine_integral() ) {
                    gun.emplace_back( gun.magazine_default() );
                }
                gun.ammo_set( default_ammo( gun.ammo_type() ), gun.ammo_capacity() );

                dump( test_npcs[ "S1" ], gun );

                if( gun.type->gun->barrel_length > 0 ) {
                    gun.emplace_back( "barrel_small" );
                    dump( test_npcs[ "S1" ], gun );
                }
            }
        }

    } else if( what == "VEHICLE" ) {
        header = {
            "Name", "Weight (empty)", "Weight (fueled)",
            "Max velocity (mph)", "Safe velocity (mph)", "Acceleration (mph/turn)",
            "Mass coeff %", "Aerodynamics coeff %", "Friction coeff %",
            "Traction coeff % (grass)"
        };
        auto dump = [&rows]( const vproto_id& obj ) {
            auto veh_empty = vehicle( obj, 0, 0 );
            auto veh_fueled = vehicle( obj, 100, 0 );

            std::vector<std::string> r;
            r.push_back( veh_empty.name );
            r.push_back( to_string( veh_empty.total_mass() ) );
            r.push_back( to_string( veh_fueled.total_mass() ) );
            r.push_back( to_string( veh_fueled.max_velocity() / 100 ) );
            r.push_back( to_string( veh_fueled.safe_velocity() / 100 ) );
            r.push_back( to_string( veh_fueled.acceleration() / 100 ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_mass() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_aerodynamics() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_friction() ) ) );
            r.push_back( to_string( (int)( 100 * veh_fueled.k_traction( veh_fueled.wheel_area( false ) / 2.0f ) ) ) );
            rows.push_back( r );
        };
        for( auto& e : vehicle_prototype::get_all() ) {
            dump( e );
        }

    } else if( what == "VPART" ) {
        header = {
            "Name", "Location", "Weight", "Size"
        };
        auto dump = [&rows]( const vpart_info &obj ) {
            std::vector<std::string> r;
            r.push_back( obj.name() );
            r.push_back( obj.location );
            r.push_back( to_string( int( ceil( item( obj.item ).weight() / 1000.0 ) ) ) );
            r.push_back( to_string( obj.size / units::legacy_volume_factor ) );
            rows.push_back( r );
        };
        for( const auto &e : vpart_info::all() ) {
            dump( e.second );
        }

    } else if( what == "AIMING" ) {
        scol = -1; // unsorted output so graph columns have predictable ordering

        const int cycles = 1400;

        header = { "Name" };
        for( int i = 0; i <= cycles; ++i ) {
            header.push_back( to_string( i ) );
        }

        auto dump = [&rows]( const standard_npc &who, const item &gun) {
            std::vector<std::string> r( 1, string_format( "%s %s", who.get_name().c_str(), gun.tname().c_str() ) );
            double penalty = MIN_RECOIL;
            for( int i = 0; i <= cycles; ++i ) {
                penalty -= who.aim_per_move( gun, penalty );
                r.push_back( string_format( "%.2f", who.gun_current_range( gun, penalty ) ) );
            }
            rows.push_back( r );
        };

        if( opts.empty() ) {
            dump( test_npcs[ "S1" ], test_items[ "G1" ] );
            dump( test_npcs[ "S1" ], test_items[ "G2" ] );
            dump( test_npcs[ "S1" ], test_items[ "G3" ] );
            dump( test_npcs[ "S1" ], test_items[ "G4" ] );

        } else {
            for( const auto &str : opts ) {
                auto idx = str.find( ':' );
                if( idx == std::string::npos ) {
                    std::cerr << "cannot parse test case: " << str << std::endl;
                    return false;
                }
                auto test = std::make_pair( test_npcs.find( str.substr( 0, idx ) ),
                                            test_items.find( str.substr( idx + 1 ) ) );

                if( test.first == test_npcs.end() || test.second == test_items.end() ) {
                    std::cerr << "invalid test case: " << str << std::endl;
                    return false;
                }

                dump( test.first->second, test.second->second );
            }
        }

    } else if( what == "EXPLOSIVE" ) {
        header = {
            // @todo Should display more useful data: shrapnel damage, safe range
            "Name", "Power", "Power at 5 tiles", "Power halves at", "Shrapnel count", "Shrapnel mass"
        };

        auto dump = [&rows]( const std::string &name, const explosion_data &ex ) {
            std::vector<std::string> r;
            r.push_back( name );
            r.push_back( to_string( ex.power ) );
            r.push_back( string_format( "%.1f", ex.power_at_range( 5.0f ) ) );
            r.push_back( string_format( "%.1f", ex.expected_range( 0.5f ) ) );
            r.push_back( to_string( ex.shrapnel.count ) );
            r.push_back( to_string( ex.shrapnel.mass ) );
            rows.push_back( r );
        };
        for( const auto& e : item_controller->get_all_itypes() ) {
            const auto &itt = e.second;
            const auto use = itt.get_use( "explosion" );
            if( use != nullptr && use->get_actor_ptr() != nullptr ) {
                const auto actor = dynamic_cast<const explosion_iuse *>( use->get_actor_ptr() );
                if( actor != nullptr ) {
                    dump( itt.nname( 1 ), actor->explosion );
                }
            }

            auto c_ex = dynamic_cast<const explosion_iuse *>( itt.countdown_action.get_actor_ptr() );
            if( c_ex != nullptr ) {
                dump( itt.nname( 1 ), c_ex->explosion );
            }
        }

    } else {
        std::cerr << "unknown argument: " << what << std::endl;
        return false;
    }

    rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string>& e ) {
        return e.empty();
    } ), rows.end() );

    if( scol >= 0 ) {
        std::sort( rows.begin(), rows.end(), [&scol]( const std::vector<std::string>& lhs, const std::vector<std::string>& rhs ) {
            return lhs[ scol ] < rhs[ scol ];
        } );
    }

    rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() );

    switch( mode ) {
        case dump_mode::TSV:
            rows.insert( rows.begin(), header );
            for( const auto& r : rows ) {
                std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) );
                std::cout << r.back() << "\n";
            }
            break;

        case dump_mode::HTML:
            std::cout << "<table>";

            std::cout << "<thead>";
            std::cout << "<tr>";
            for( const auto& col : header ) {
                std::cout << "<th>" << col << "</th>";
            }
            std::cout << "</tr>";
            std::cout << "</thead>";

            std::cout << "<tdata>";
            for( const auto& r : rows ) {
                std::cout << "<tr>";
                for( const auto& col : r ) {
                    std::cout << "<td>" << col << "</td>";
                }
                std::cout << "</tr>";
            }
            std::cout << "</tdata>";

            std::cout << "</table>";
            break;
    }

    return true;
}
示例#19
0
void game::dump_stats( const std::string& what, dump_mode mode )
{
    load_core_data();
    DynamicDataLoader::get_instance().finalize_loaded_data();

    std::vector<std::string> header;
    std::vector<std::vector<std::string>> rows;

    if( what == "AMMO" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Stack",
            "Range", "Dispersion", "Recoil", "Damage", "Pierce"
        };
        auto dump = [&rows]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( obj.type->ammo->type );
            r.push_back( std::to_string( obj.volume() ) );
            r.push_back( std::to_string( obj.weight() ) );
            r.push_back( std::to_string( obj.type->stack_size ) );
            r.push_back( std::to_string( obj.type->ammo->range ) );
            r.push_back( std::to_string( obj.type->ammo->dispersion ) );
            r.push_back( std::to_string( obj.type->ammo->recoil ) );
            r.push_back( std::to_string( obj.type->ammo->damage ) );
            r.push_back( std::to_string( obj.type->ammo->pierce ) );
            rows.push_back( r );
        };
        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second->ammo ) {
                dump( item( e.first, calendar::turn, item::solitary_tag {} ) );
            }
        }

    } else if( what == "EDIBLE" ) {
        header = {
            "Name", "Volume", "Weight", "Stack", "Calories", "Quench", "Healthy"
        };
        for( const auto& v : vitamin::all() ) {
             header.push_back( v.second.name() );
        }
        auto dump = [&rows]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( std::to_string( obj.volume() ) );
            r.push_back( std::to_string( obj.weight() ) );
            r.push_back( std::to_string( obj.type->stack_size ) );
            r.push_back( std::to_string( obj.type->comestible->get_calories() ) );
            r.push_back( std::to_string( obj.type->comestible->quench ) );
            r.push_back( std::to_string( obj.type->comestible->healthy ) );
            auto vits = g->u.vitamins_from( obj );
            for( const auto& v : vitamin::all() ) {
                 r.push_back( std::to_string( vits[ v.first ] ) );
            }
            rows.push_back( r );
        };
        for( auto& e : item_controller->get_all_itypes() ) {
            if( e.second->comestible &&
                ( e.second->comestible->comesttype == "FOOD" ||
                  e.second->comestible->comesttype == "DRINK" ) ) {

                item food( e.first, calendar::turn, item::solitary_tag {} );
                if( g->u.can_eat( food, false, true ) == EDIBLE ) {
                    dump( food );
                }
            }
        }

    } else if( what == "GUN" ) {
        header = {
            "Name", "Ammo", "Volume", "Weight", "Capacity",
            "Range", "Dispersion", "Recoil", "Damage", "Pierce"
        };
        std::set<std::string> locations;
        for( const auto& e : item_controller->get_all_itypes() ) {
            if( e.second->gun ) {
                std::transform( e.second->gun->valid_mod_locations.begin(),
                                e.second->gun->valid_mod_locations.end(),
                                std::inserter( locations, locations.begin() ),
                                []( const std::pair<std::string, int>& e ) { return e.first; } );
            }
        }
        for( const auto &e : locations ) {
            header.push_back( e );
        }

        auto dump = [&rows,&locations]( const item& obj ) {
            std::vector<std::string> r;
            r.push_back( obj.tname( false ) );
            r.push_back( obj.ammo_type() != "NULL" ? obj.ammo_type() : "" );
            r.push_back( std::to_string( obj.volume() ) );
            r.push_back( std::to_string( obj.weight() ) );
            r.push_back( std::to_string( obj.ammo_capacity() ) );
            r.push_back( std::to_string( obj.gun_range() ) );
            r.push_back( std::to_string( obj.gun_dispersion() ) );
            r.push_back( std::to_string( obj.gun_recoil() ) );
            r.push_back( std::to_string( obj.gun_damage() ) );
            r.push_back( std::to_string( obj.gun_pierce() ) );
            for( const auto &e : locations ) {
                r.push_back( std::to_string( obj.type->gun->valid_mod_locations[ e ] ) );
            }
            rows.push_back( r );
        };
        for( const auto& e : item_controller->get_all_itypes() ) {
            if( e.second->gun ) {
                item gun( e.first );
                if( gun.is_reloadable() ) {
                    gun.ammo_set( default_ammo( gun.ammo_type() ), gun.ammo_capacity() );
                }
                dump( gun );

                if( gun.type->gun->barrel_length > 0 ) {
                    gun.emplace_back( "barrel_small" );
                    dump( gun );
                }
            }
        }

    } else if( what == "VEHICLE" ) {
        header = {
            "Name", "Weight (empty)", "Weight (fueled)"
        };
        auto dump = [&rows]( const vproto_id& obj ) {
            auto veh_empty = vehicle( obj, 0, 0 );
            auto veh_fueled = vehicle( obj, 100, 0 );

            std::vector<std::string> r;
            r.push_back( veh_empty.name );
            r.push_back( std::to_string( veh_empty.total_mass() ) );
            r.push_back( std::to_string( veh_fueled.total_mass() ) );
            rows.push_back( r );
        };
        for( auto& e : vehicle_prototype::get_all() ) {
            dump( e );
        }

    } else if( what == "VPART" ) {
        header = {
            "Name", "Location", "Weight", "Size"
        };
        auto dump = [&rows]( const vpart_info *obj ) {
            std::vector<std::string> r;
            r.push_back( obj->name() );
            r.push_back( obj->location );
            r.push_back( std::to_string( int( ceil( item( obj->item ).weight() / 1000.0 ) ) ) );
            r.push_back( std::to_string( obj->size ) );
            rows.push_back( r );
        };
        for( const auto e : vpart_info::get_all() ) {
            dump( e );
        }
    }

    rows.erase( std::remove_if( rows.begin(), rows.end(), []( const std::vector<std::string>& e ) {
        return e.empty();
    } ), rows.end() );

    std::sort( rows.begin(), rows.end(), []( const std::vector<std::string>& lhs, const std::vector<std::string>& rhs ) {
        return lhs[ 0 ] < rhs[ 0 ];
    } );

    rows.erase( std::unique( rows.begin(), rows.end() ), rows.end() );

    switch( mode ) {
        case dump_mode::TSV:
            rows.insert( rows.begin(), header );
            for( const auto& r : rows ) {
                std::copy( r.begin(), r.end() - 1, std::ostream_iterator<std::string>( std::cout, "\t" ) );
                std::cout << r.back() << "\n";
            }
            break;

        case dump_mode::HTML:
            std::cout << "<table>";

            std::cout << "<thead>";
            std::cout << "<tr>";
            for( const auto& col : header ) {
                std::cout << "<th>" << col << "</th>";
            }
            std::cout << "</tr>";
            std::cout << "</thead>";

            std::cout << "<tdata>";
            for( const auto& r : rows ) {
                std::cout << "<tr>";
                for( const auto& col : r ) {
                    std::cout << "<td>" << col << "</td>";
                }
                std::cout << "</tr>";
            }
            std::cout << "</tdata>";

            std::cout << "</table>";
            break;
    }
}