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; };
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)); } }
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; };
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); }
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; }
//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); } }
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; }
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; }
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; }
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; } }