71 #include <fmt/format.h>
92 this->DisjoinInterActorBeams();
95 ar_node_to_beam_connections.clear();
96 ar_node_to_node_connections.clear();
99 if (ar_dashboard !=
nullptr)
102 ar_dashboard =
nullptr;
112 for (
int i = 0; i < ar_num_soundsources; i++)
114 if (ar_soundsources[i].ssi)
117 ar_soundsources[i].ssi =
nullptr;
120 ar_num_soundsources = 0;
123 if (ar_engine !=
nullptr)
129 if (ar_autopilot !=
nullptr)
132 ar_autopilot =
nullptr;
135 if (m_fusealge_airfoil)
136 delete m_fusealge_airfoil;
137 m_fusealge_airfoil =
nullptr;
139 if (m_replay_handler)
140 delete m_replay_handler;
141 m_replay_handler =
nullptr;
143 ar_vehicle_ai =
nullptr;
146 if (m_deletion_scene_nodes.size() > 0)
148 for (
unsigned int i = 0; i < m_deletion_scene_nodes.size(); i++)
150 if (!m_deletion_scene_nodes[i])
152 m_deletion_scene_nodes[i]->removeAndDestroyAllChildren();
155 m_deletion_scene_nodes.clear();
158 if (m_deletion_entities.size() > 0)
160 for (
unsigned int i = 0; i < m_deletion_entities.size(); i++)
162 if (!m_deletion_entities[i])
164 m_deletion_entities[i]->detachAllObjectsFromBone();
167 m_deletion_entities.clear();
173 for (
int i = 0; i < ar_num_wings; i++)
177 delete ar_wings[i].fa;
178 if (ar_wings[i].cnode)
180 ar_wings[i].cnode->removeAndDestroyAllChildren();
186 for (
int i = 0; i < ar_num_aeroengines; i++)
188 if (ar_aeroengines[i])
189 delete ar_aeroengines[i];
193 for (
int i = 0; i < ar_num_screwprops; i++)
195 if (ar_screwprops[i])
197 delete ar_screwprops[i];
198 ar_screwprops[i] =
nullptr;
207 ar_airbrakes.clear();
210 for (
int i = 0; i < ar_num_wheels; ++i)
212 delete m_skid_trails[i];
213 m_skid_trails[i] =
nullptr;
217 for (
size_t i = 0; i < this->ar_flares.size(); i++)
219 if (ar_flares[i].snode)
221 ar_flares[i].snode->removeAndDestroyAllChildren();
224 if (ar_flares[i].bbs)
226 if (ar_flares[i].light)
229 this->ar_flares.clear();
232 for (std::vector<exhaust_t>::iterator it = exhausts.begin(); it != exhausts.end(); it++)
236 it->smokeNode->removeAndDestroyAllChildren();
241 it->smoker->removeAllAffectors();
242 it->smoker->removeAllEmitters();
248 for (
int i = 0; i < ar_num_custom_particles; i++)
250 if (ar_custom_particles[i].snode)
252 ar_custom_particles[i].snode->removeAndDestroyAllChildren();
255 if (ar_custom_particles[i].psys)
257 ar_custom_particles[i].psys->removeAllAffectors();
258 ar_custom_particles[i].psys->removeAllEmitters();
264 for (std::vector<RailGroup*>::iterator it = m_railgroups.begin(); it != m_railgroups.end(); it++)
268 m_railgroups.clear();
270 if (m_intra_point_col_detector)
272 delete m_intra_point_col_detector;
273 m_intra_point_col_detector =
nullptr;
276 if (m_inter_point_col_detector)
278 delete m_inter_point_col_detector;
279 m_inter_point_col_detector =
nullptr;
283 delete m_transfer_case;
285 for (
int i = 0; i < m_num_axle_diffs; ++i)
287 if (m_axle_diffs[i] !=
nullptr)
288 delete m_axle_diffs[i];
290 m_num_axle_diffs = 0;
292 for (
int i = 0; i < m_num_wheel_diffs; ++i)
294 if (m_wheel_diffs[i] !=
nullptr)
295 delete m_wheel_diffs[i];
297 m_num_wheel_diffs = 0;
301 m_wheel_node_count = 0;
306 delete[] ar_rotators;
311 ar_state = ActorState::DISPOSED;
316 void Actor::scaleTruck(
float value)
318 if (ar_state == ActorState::DISPOSED)
325 for (
int i = 0; i < ar_num_beams; i++)
328 ar_beams[i].d *= value;
329 ar_beams[i].L *= value;
330 ar_beams[i].refL *= value;
335 hbeam.hb_ref_length *= value;
336 hbeam.hb_speed *= value;
339 Vector3 refpos = ar_nodes[0].AbsPosition;
340 Vector3 relpos = ar_nodes[0].RelPosition;
341 for (
int i = 1; i < ar_num_nodes; i++)
343 ar_initial_node_positions[i] = refpos + (ar_initial_node_positions[i] - refpos) * value;
344 ar_nodes[i].AbsPosition = refpos + (ar_nodes[i].AbsPosition - refpos) * value;
345 ar_nodes[i].RelPosition = relpos + (ar_nodes[i].RelPosition - relpos) * value;
346 ar_nodes[i].Velocity *= value;
347 ar_nodes[i].Forces *= value;
348 ar_nodes[i].mass *= value;
350 updateSlideNodePositions();
352 m_gfx_actor->ScaleActor(relpos, value);
356 float Actor::getRotation()
358 if (ar_state == ActorState::DISPOSED)
361 Vector3 dir = getDirection();
363 return atan2(dir.dotProduct(Vector3::UNIT_X), dir.dotProduct(-Vector3::UNIT_Z));
366 Vector3 Actor::getDirection()
368 return ar_main_camera_dir_corr * this->GetCameraDir();
371 Vector3 Actor::getPosition()
373 return m_avg_node_position;
376 Ogre::Quaternion Actor::getOrientation()
378 Ogre::Vector3 localZ = ar_main_camera_dir_corr * -this->GetCameraDir();
379 Ogre::Vector3 localX = ar_main_camera_dir_corr * this->GetCameraRoll();
380 Ogre::Vector3 localY = localZ.crossProduct(localX);
381 return Ogre::Quaternion(localX, localY, localZ);
384 void Actor::pushNetwork(
char* data,
int size)
390 update.
node_data.resize(m_net_node_buf_size);
391 update.
wheel_data.resize(ar_num_wheels *
sizeof(
float));
404 memcpy(update.
node_data.data(), ptr, m_net_node_buf_size);
405 ptr += m_net_node_buf_size;
408 for (
int i = 0; i < ar_num_wheels; i++)
410 float wspeed = *(
float*)(ptr);
412 ptr +=
sizeof(float);
416 for (
size_t i = 0; i < m_prop_anim_key_states.size(); i++)
419 char byte = *(ptr + (i / 8));
420 char mask = char(1) << (7 - (i % 8));
421 m_prop_anim_key_states[i].anim_active = (
byte & mask);
426 if (!m_net_initialized)
434 strncpy(reg.
name, ar_filename.c_str(), 128);
443 text << info.
username <<
_L(
" content mismatch: ") << reg.name;
450 m_net_initialized =
true;
452 RoR::LogFormat(
"[RoR|Network] Stream mismatch, filename: '%s'", ar_filename.c_str());
457 if (!m_net_initialized)
461 int rnow = std::max(0, tnow +
App::GetGameContext()->GetActorManager()->GetNetTimeOffset(ar_net_source_id));
462 if (oob->
time > rnow + 100)
468 m_net_updates.push_back(update);
469 #endif // USE_SOCKETW
472 void Actor::calcNetwork()
476 if (m_net_updates.size() < 2)
480 int rnow = std::max(0, tnow +
App::GetGameContext()->GetActorManager()->GetNetTimeOffset(ar_net_source_id));
483 int index_offset = 0;
484 for (
int i = 0; i < m_net_updates.size() - 1; i++)
487 if (oob->
time > rnow)
494 char* netb1 = (
char*) m_net_updates[index_offset ].node_data.data();
495 char* netb2 = (
char*) m_net_updates[index_offset + 1].node_data.data();
496 float* net_rp1 = (
float*) m_net_updates[index_offset ].wheel_data.data();
497 float* net_rp2 = (
float*) m_net_updates[index_offset + 1].wheel_data.data();
499 float tratio = (float)(rnow - oob1->
time) / (float)(oob2->
time - oob1->
time);
503 m_net_updates.clear();
506 else if (tratio > 1.0f)
510 else if (index_offset == 0 && (m_net_updates.size() > 5 || (tratio < 0.125f && m_net_updates.size() > 2)))
515 short* sp1 = (
short*)(netb1 +
sizeof(
float) * 3);
516 short* sp2 = (
short*)(netb2 +
sizeof(
float) * 3);
517 Vector3 p1ref = Vector3::ZERO;
518 Vector3 p2ref = Vector3::ZERO;
519 Vector3 p1 = Vector3::ZERO;
520 Vector3 p2 = Vector3::ZERO;
522 for (
int i = 0; i < m_net_first_wheel_node; i++)
527 p1.x = ((
float*)netb1)[0];
528 p1.y = ((
float*)netb1)[1];
529 p1.z = ((
float*)netb1)[2];
532 p2.x = ((
float*)netb2)[0];
533 p2.y = ((
float*)netb2)[1];
534 p2.z = ((
float*)netb2)[2];
541 p1.x = (float)(sp1[(i - 1) * 3 + 0]) / m_net_node_compression;
542 p1.y = (float)(sp1[(i - 1) * 3 + 1]) / m_net_node_compression;
543 p1.z = (float)(sp1[(i - 1) * 3 + 2]) / m_net_node_compression;
546 p2.x = (float)(sp2[(i - 1) * 3 + 0]) / m_net_node_compression;
547 p2.y = (float)(sp2[(i - 1) * 3 + 1]) / m_net_node_compression;
548 p2.z = (float)(sp2[(i - 1) * 3 + 2]) / m_net_node_compression;
553 ar_nodes[i].AbsPosition = p1 + tratio * (p2 - p1);
554 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
555 ar_nodes[i].Velocity = (p2 - p1) * 1000.0f / (
float)(oob2->
time - oob1->
time);
558 for (
int i = 0; i < ar_num_wheels; i++)
560 float rp = net_rp1[i] + tratio * (net_rp2[i] - net_rp1[i]);
562 Vector3 axis = ar_wheels[i].wh_axis_node_1->RelPosition - ar_wheels[i].wh_axis_node_0->RelPosition;
564 Plane pplan = Plane(axis, ar_wheels[i].wh_axis_node_0->AbsPosition);
565 Vector3 ortho = -pplan.projectVector(ar_wheels[i].wh_near_attach_node->AbsPosition) - ar_wheels[i].wh_axis_node_0->AbsPosition;
566 Vector3 ray = ortho.crossProduct(axis);
568 ray *= ar_wheels[i].wh_radius;
569 float drp = Math::TWO_PI / (ar_wheels[i].wh_num_nodes / 2);
570 for (
int j = 0; j < ar_wheels[i].wh_num_nodes / 2; j++)
572 Vector3 uray = Quaternion(Radian(rp - drp * j), axis) * ray;
574 ar_wheels[i].wh_nodes[j * 2 + 0]->AbsPosition = ar_wheels[i].wh_axis_node_0->AbsPosition + uray;
575 ar_wheels[i].wh_nodes[j * 2 + 0]->RelPosition = ar_wheels[i].wh_nodes[j * 2]->AbsPosition - ar_origin;
577 ar_wheels[i].wh_nodes[j * 2 + 1]->AbsPosition = ar_wheels[i].wh_axis_node_1->AbsPosition + uray;
578 ar_wheels[i].wh_nodes[j * 2 + 1]->RelPosition = ar_wheels[i].wh_nodes[j * 2 + 1]->AbsPosition - ar_origin;
581 ray *= ar_wheels[i].wh_rim_radius;
582 for (
int j = 0; j < ar_wheels[i].wh_num_rim_nodes / 2; j++)
584 Vector3 uray = Quaternion(Radian(rp - drp * j), axis) * ray;
586 ar_wheels[i].wh_rim_nodes[j * 2 + 0]->AbsPosition = ar_wheels[i].wh_axis_node_0->AbsPosition + uray;
587 ar_wheels[i].wh_rim_nodes[j * 2 + 0]->RelPosition = ar_wheels[i].wh_rim_nodes[j * 2]->AbsPosition - ar_origin;
589 ar_wheels[i].wh_rim_nodes[j * 2 + 1]->AbsPosition = ar_wheels[i].wh_axis_node_1->AbsPosition + uray;
590 ar_wheels[i].wh_rim_nodes[j * 2 + 1]->RelPosition = ar_wheels[i].wh_rim_nodes[j * 2 + 1]->AbsPosition - ar_origin;
593 this->UpdateBoundingBoxes();
594 this->calculateAveragePosition();
603 ar_wheel_speed = netwspeed;
613 if (ar_num_aeroengines > 0)
635 ar_engine->PushNetworkState(engspeed, engforce, engclutch, gear, running, contact, automode);
640 toggleCustomParticles();
646 this->setLightStateMask(oob1->
lightmask);
658 for (
int i = 0; i < index_offset; i++)
660 m_net_updates.pop_front();
663 m_net_initialized =
true;
666 void Actor::RecalculateNodeMasses(Real total)
669 for (
int i = 0; i < ar_num_nodes; i++)
671 if (!ar_nodes[i].nd_tyre_node)
673 if (!ar_nodes[i].nd_loaded_mass)
675 ar_nodes[i].mass = 0;
677 else if (!ar_nodes[i].nd_override_mass)
679 ar_nodes[i].mass = m_load_mass / (float)m_masscount;
685 for (
int i = 0; i < ar_num_beams; i++)
689 Real half_newlen = ar_beams[i].L / 2.0;
690 if (!ar_beams[i].p1->nd_tyre_node)
692 if (!ar_beams[i].p2->nd_tyre_node)
697 for (
int i = 0; i < ar_num_beams; i++)
701 Real half_mass = ar_beams[i].L * total / len / 2.0f;
702 if (!ar_beams[i].p1->nd_tyre_node)
703 ar_beams[i].p1->mass += half_mass;
704 if (!ar_beams[i].p2->nd_tyre_node)
705 ar_beams[i].p2->mass += half_mass;
709 for (std::vector<rope_t>::iterator it = ar_ropes.begin(); it != ar_ropes.end(); it++)
711 it->rp_beam->p2->mass = 100.0f;
715 for (
int i = 0; i < this->ar_num_cinecams; ++i)
718 ar_nodes[ar_cinecam_node[i]].mass = m_definition->root_module->cinecam[i].node_mass;
722 for (
int i = 0; i < ar_num_nodes; i++)
724 if (!ar_nodes[i].nd_tyre_node &&
725 !(ar_minimass_skip_loaded_nodes && ar_nodes[i].nd_loaded_mass) &&
726 ar_nodes[i].mass < ar_minimass[i])
731 snprintf(buf, 300,
"Node '%d' mass (%f Kg) is too light. Resetting to 'minimass' (%f Kg)", i, ar_nodes[i].mass, ar_minimass[i]);
734 ar_nodes[i].mass = ar_minimass[i];
739 for (
int i = 0; i < ar_num_nodes; i++)
743 String msg =
"Node " +
TOSTRING(i) +
" : " +
TOSTRING((
int)ar_nodes[i].mass) +
" kg";
744 if (ar_nodes[i].nd_loaded_mass)
746 if (ar_nodes[i].nd_override_mass)
747 msg +=
" (overriden by node mass)";
749 msg +=
" (normal load node: " +
TOSTRING(m_load_mass) +
" kg / " +
TOSTRING(m_masscount) +
" nodes)";
753 m_total_mass += ar_nodes[i].mass;
755 LOG(
"TOTAL VEHICLE MASS: " +
TOSTRING((
int)m_total_mass) +
" kg");
758 float Actor::getTotalMass(
bool withLocked)
760 if (ar_state == ActorState::DISPOSED)
766 float mass = m_total_mass;
768 for (
ActorPtr& actor : ar_linked_actors)
770 mass += actor->m_total_mass;
776 void Actor::DetermineLinkedActors()
780 ar_linked_actors.clear();
783 std::map<ActorPtr, bool> lookup_table;
785 lookup_table.insert(std::pair<ActorPtr, bool>(
this,
false));
791 for (
auto it_actor = lookup_table.begin(); it_actor != lookup_table.end(); ++it_actor)
793 if (!it_actor->second)
798 auto actor_pair = inter_actor_link.second;
799 if (actor == actor_pair.first || actor == actor_pair.second)
801 auto other_actor = (actor != actor_pair.first) ? actor_pair.first : actor_pair.second;
802 auto ret = lookup_table.insert(std::pair<ActorPtr, bool>(other_actor,
false));
805 ar_linked_actors.push_back(other_actor);
810 it_actor->second =
true;
816 int Actor::getWheelNodeCount()
const
818 return m_wheel_node_count;
821 void Actor::calcNodeConnectivityGraph()
825 ar_node_to_node_connections.resize(ar_num_nodes, std::vector<int>());
826 ar_node_to_beam_connections.resize(ar_num_nodes, std::vector<int>());
828 for (i = 0; i < ar_num_beams; i++)
830 if (ar_beams[i].p1 != NULL && ar_beams[i].p2 != NULL && ar_beams[i].p1->pos >= 0 && ar_beams[i].p2->pos >= 0)
832 ar_node_to_node_connections[ar_beams[i].p1->pos].push_back(ar_beams[i].p2->pos);
833 ar_node_to_beam_connections[ar_beams[i].p1->pos].push_back(i);
834 ar_node_to_node_connections[ar_beams[i].p2->pos].push_back(ar_beams[i].p1->pos);
835 ar_node_to_beam_connections[ar_beams[i].p2->pos].push_back(i);
840 bool Actor::Intersects(
ActorPtr actor, Vector3 offset)
842 Vector3 bb_min = ar_bounding_box.getMinimum() + offset;
843 Vector3 bb_max = ar_bounding_box.getMaximum() + offset;
844 AxisAlignedBox bb = AxisAlignedBox(bb_min, bb_max);
850 for (
int i = 0; i < ar_num_beams; i++)
852 if (!(ar_beams[i].p1->nd_contacter || ar_beams[i].p1->nd_contactable) ||
853 !(ar_beams[i].p2->nd_contacter || ar_beams[i].p2->nd_contactable))
856 Vector3 origin = ar_beams[i].p1->AbsPosition + offset;
857 Vector3 target = ar_beams[i].p2->AbsPosition + offset;
859 Ray ray(origin, target - origin);
868 auto result = Ogre::Math::intersects(ray, a, b, c);
869 if (result.first && result.second < 1.0f)
886 Ray ray(origin, target - origin);
888 for (
int j = 0; j < ar_num_collcabs; j++)
890 int index = ar_collcabs[j] * 3;
891 Vector3 a = ar_nodes[ar_cabs[index + 0]].AbsPosition + offset;
892 Vector3 b = ar_nodes[ar_cabs[index + 1]].AbsPosition + offset;
893 Vector3 c = ar_nodes[ar_cabs[index + 2]].AbsPosition + offset;
895 auto result = Ogre::Math::intersects(ray, a, b, c);
896 if (result.first && result.second < 1.0f)
906 Vector3 Actor::calculateCollisionOffset(Vector3 direction)
908 if (direction == Vector3::ZERO)
909 return Vector3::ZERO;
911 Real max_distance = direction.normalise();
914 Vector3 collision_offset = Vector3::ZERO;
916 while (collision_offset.length() < max_distance)
918 Vector3 bb_min = ar_bounding_box.getMinimum() + collision_offset;
919 Vector3 bb_max = ar_bounding_box.getMaximum() + collision_offset;
920 AxisAlignedBox bb = AxisAlignedBox(bb_min, bb_max);
922 bool collision =
false;
928 if (!bb.intersects(actor->ar_bounding_box))
932 if (m_intra_point_col_detector)
934 for (
int i = 0; i < actor->ar_num_collcabs; i++)
936 int tmpv = actor->ar_collcabs[i] * 3;
937 node_t* no = &actor->ar_nodes[actor->ar_cabs[tmpv]];
938 node_t* na = &actor->ar_nodes[actor->ar_cabs[tmpv + 1]];
939 node_t* nb = &actor->ar_nodes[actor->ar_cabs[tmpv + 2]];
941 m_intra_point_col_detector->query(no->
AbsPosition - collision_offset,
944 actor->ar_collision_range * 3.0f);
946 if (collision = !m_intra_point_col_detector->hit_list.empty())
954 float proximity = std::max(.05f, std::sqrt(std::max(m_min_camera_radius, actor->m_min_camera_radius)) / 50.f);
957 for (
int i = 0; i < ar_num_nodes; i++)
959 if (!ar_nodes[i].nd_contacter && !ar_nodes[i].nd_contactable)
962 Vector3 query_position = ar_nodes[i].AbsPosition + collision_offset;
964 for (
int j = 0; j < actor->ar_num_nodes; j++)
966 if (!actor->ar_nodes[j].nd_contacter && !actor->ar_nodes[j].nd_contactable)
969 if (collision = query_position.squaredDistance(actor->ar_nodes[j].AbsPosition) < proximity)
982 if (!collision && m_inter_point_col_detector)
984 for (
int i = 0; i < ar_num_collcabs; i++)
986 int tmpv = ar_collcabs[i] * 3;
987 node_t* no = &ar_nodes[ar_cabs[tmpv]];
988 node_t* na = &ar_nodes[ar_cabs[tmpv + 1]];
989 node_t* nb = &ar_nodes[ar_cabs[tmpv + 2]];
991 m_inter_point_col_detector->query(no->
AbsPosition + collision_offset,
994 ar_collision_range * 3.0f);
996 if (collision = !m_inter_point_col_detector->hit_list.empty())
1008 if (collision = this->Intersects(actor, collision_offset))
1016 collision_offset += direction * 0.05f;
1019 return collision_offset;
1022 void Actor::resolveCollisions(Ogre::Vector3 direction)
1024 if (m_intra_point_col_detector)
1025 m_intra_point_col_detector->UpdateIntraPoint(
true);
1027 if (m_inter_point_col_detector)
1028 m_inter_point_col_detector->UpdateInterPoint(
true);
1030 Vector3 offset = calculateCollisionOffset(direction);
1032 if (offset == Vector3::ZERO)
1036 offset += 0.2f * Vector3(offset.x, 0.0f, offset.z).normalisedCopy();
1038 resetPosition(ar_nodes[0].AbsPosition.x + offset.x, ar_nodes[0].AbsPosition.z + offset.z,
false, this->getMinHeight() + offset.y);
1041 void Actor::resolveCollisions(
float max_distance,
bool consider_up)
1043 if (m_intra_point_col_detector)
1044 m_intra_point_col_detector->UpdateIntraPoint(
true);
1046 if (m_inter_point_col_detector)
1047 m_inter_point_col_detector->UpdateInterPoint(
true);
1049 Vector3 u = Vector3::UNIT_Y;
1050 Vector3 f = Vector3(getDirection().
x, 0.0f, getDirection().
z).normalisedCopy();
1051 Vector3 l = u.crossProduct(f);
1054 Vector3 left = calculateCollisionOffset(+l * max_distance);
1055 Vector3 right = calculateCollisionOffset(-l * left.length());
1056 Vector3 lateral = left.length() < right.length() * 1.1f ? left : right;
1058 Vector3 front = calculateCollisionOffset(+f * lateral.length());
1059 Vector3 back = calculateCollisionOffset(-f * front.length());
1060 Vector3 sagittal = front.length() < back.length() * 1.1f ? front : back;
1062 Vector3 offset = lateral.length() < sagittal.length() * 1.2f ? lateral : sagittal;
1066 Vector3 up = calculateCollisionOffset(+u * offset.length());
1067 if (up.length() * 1.2f < offset.length())
1071 if (offset == Vector3::ZERO)
1075 offset += 0.2f * Vector3(offset.x, 0.0f, offset.z).normalisedCopy();
1077 resetPosition(ar_nodes[0].AbsPosition.x + offset.x, ar_nodes[0].AbsPosition.z + offset.z,
true, this->getMinHeight() + offset.y);
1080 void Actor::calculateAveragePosition()
1085 m_avg_node_position = ar_nodes[ar_custom_camera_node].AbsPosition;
1087 else if (ar_extern_camera_mode == ExtCameraMode::CINECAM && ar_num_cinecams > 0)
1090 m_avg_node_position = ar_nodes[ar_cinecam_node[0]].AbsPosition;
1092 else if (ar_extern_camera_mode == ExtCameraMode::NODE && ar_extern_camera_node !=
NODENUM_INVALID)
1095 m_avg_node_position = ar_nodes[ar_extern_camera_node].AbsPosition;
1100 Vector3 aposition = Vector3::ZERO;
1101 for (
int n = 0; n < ar_num_nodes; n++)
1103 aposition += ar_nodes[n].AbsPosition;
1105 m_avg_node_position = aposition / ar_num_nodes;
1115 void Actor::UpdateBoundingBoxes()
1118 ar_bounding_box = AxisAlignedBox::BOX_NULL;
1119 ar_predicted_bounding_box = AxisAlignedBox::BOX_NULL;
1120 ar_evboxes_bounding_box = AxisAlignedBox::BOX_NULL;
1121 for (
size_t i = 0; i < ar_collision_bounding_boxes.size(); ++i)
1123 ar_collision_bounding_boxes[i] = AxisAlignedBox::BOX_NULL;
1124 ar_predicted_coll_bounding_boxes[i] = AxisAlignedBox::BOX_NULL;
1129 const float CABNODE_MAX_CAMDIST = 15.f;
1130 const Ogre::Vector3 mainCamPos = ar_nodes[ar_main_camera_node_pos].RelPosition;
1133 for (
int i = 0; i < ar_num_nodes; i++)
1135 Vector3 vel = ar_nodes[i].Velocity;
1136 Vector3 pos = ar_nodes[i].AbsPosition;
1137 int16_t cid = ar_nodes[i].nd_coll_bbox_id;
1139 ar_bounding_box.merge(pos);
1140 if (mainCamPos.squaredDistance(ar_nodes[i].RelPosition) < (CABNODE_MAX_CAMDIST*CABNODE_MAX_CAMDIST))
1142 ar_evboxes_bounding_box.merge(pos);
1144 ar_predicted_bounding_box.merge(pos);
1145 ar_predicted_bounding_box.merge(pos + vel);
1146 if (cid != node_t::INVALID_BBOX)
1148 ar_collision_bounding_boxes[cid].merge(pos);
1149 ar_predicted_coll_bounding_boxes[cid].merge(pos);
1150 ar_predicted_coll_bounding_boxes[cid].merge(pos + vel);
1157 for (
size_t i = 0; i < ar_collision_bounding_boxes.size(); ++i)
1164 void Actor::UpdatePhysicsOrigin()
1166 if (ar_nodes[0].RelPosition.squaredLength() > 10000.0)
1168 Vector3 offset = ar_nodes[0].RelPosition;
1169 ar_origin += offset;
1170 for (
int i = 0; i < ar_num_nodes; i++)
1172 ar_nodes[i].RelPosition -= offset;
1177 void Actor::ResetAngle(
float rot)
1180 Vector3 origin = ar_nodes[ar_main_camera_node_pos].AbsPosition;
1184 matrix.FromEulerAnglesXYZ(Radian(0), Radian(-rot + m_spawn_rotation), Radian(0));
1186 for (
int i = 0; i < ar_num_nodes; i++)
1189 ar_nodes[i].AbsPosition -= origin;
1190 ar_nodes[i].AbsPosition = matrix * ar_nodes[i].AbsPosition;
1191 ar_nodes[i].AbsPosition += origin;
1192 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - this->ar_origin;
1195 this->UpdateBoundingBoxes();
1196 calculateAveragePosition();
1199 void Actor::updateInitPosition()
1201 for (
int i = 0; i < ar_num_nodes; i++)
1203 ar_initial_node_positions[i] = ar_nodes[i].AbsPosition;
1207 void Actor::resetPosition(
float px,
float pz,
bool setInitPosition,
float miny)
1210 Vector3 offset = Vector3(px, ar_nodes[0].AbsPosition.y, pz) - ar_nodes[0].AbsPosition;
1211 for (
int i = 0; i < ar_num_nodes; i++)
1213 ar_nodes[i].AbsPosition += offset;
1214 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1218 float vertical_offset = miny - this->getMinHeight();
1221 vertical_offset += std::max(0.0f,
App::GetGameContext()->GetTerrain()->getWater()->GetStaticWaterHeight() - miny);
1223 for (
int i = 1; i < ar_num_nodes; i++)
1225 if (ar_nodes[i].nd_no_ground_contact)
1228 vertical_offset += std::max(0.0f, terrainHeight - (ar_nodes[i].AbsPosition.y + vertical_offset));
1230 for (
int i = 0; i < ar_num_nodes; i++)
1232 ar_nodes[i].AbsPosition.y += vertical_offset;
1233 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1237 float mesh_offset = 0.0f;
1238 for (
int i = 0; i < ar_num_nodes; i++)
1240 if (mesh_offset >= 1.0f)
1242 if (ar_nodes[i].nd_no_ground_contact)
1244 float offset = mesh_offset;
1245 while (offset < 1.0f)
1247 Vector3 query = ar_nodes[i].AbsPosition + Vector3(0.0f, offset, 0.0f);
1248 if (!
App::GetGameContext()->GetTerrain()->GetCollisions()->collisionCorrect(&query,
false))
1250 mesh_offset = offset;
1256 for (
int i = 0; i < ar_num_nodes; i++)
1258 ar_nodes[i].AbsPosition.y += mesh_offset;
1259 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1262 resetPosition(Vector3::ZERO, setInitPosition);
1265 void Actor::resetPosition(Ogre::Vector3 translation,
bool setInitPosition)
1268 if (translation != Vector3::ZERO)
1270 Vector3 offset = translation - ar_nodes[0].AbsPosition;
1271 for (
int i = 0; i < ar_num_nodes; i++)
1273 ar_nodes[i].AbsPosition += offset;
1274 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1278 if (setInitPosition)
1280 for (
int i = 0; i < ar_num_nodes; i++)
1282 ar_initial_node_positions[i] = ar_nodes[i].AbsPosition;
1286 this->UpdateBoundingBoxes();
1287 calculateAveragePosition();
1290 void Actor::mouseMove(
NodeNum_t node, Vector3 pos,
float force)
1292 m_mouse_grab_node = node;
1293 m_mouse_grab_move_force = force * std::pow(m_total_mass / 3000.0f, 0.75f);
1294 m_mouse_grab_pos = pos;
1297 void Actor::toggleWheelDiffMode()
1299 for (
int i = 0; i < m_num_wheel_diffs; ++i)
1301 m_wheel_diffs[i]->ToggleDifferentialMode();
1305 void Actor::toggleAxleDiffMode()
1307 for (
int i = 0; i < m_num_axle_diffs; ++i)
1309 m_axle_diffs[i]->ToggleDifferentialMode();
1313 void Actor::displayAxleDiffMode()
1315 if (m_num_axle_diffs == 0)
1318 _L(
"No inter-axle differential installed on current vehicle!"),
"error.png");
1322 String message =
"";
1323 for (
int i = 0; i < m_num_axle_diffs; ++i)
1325 if (m_axle_diffs[i])
1330 int a1 = m_axle_diffs[i]->di_idx_1 + 1;
1331 int a2 = m_axle_diffs[i]->di_idx_2 + 1;
1333 message += m_axle_diffs[i]->GetDifferentialTypeName();
1337 "Inter-axle differentials:\n" + message,
"cog.png");
1341 void Actor::displayWheelDiffMode()
1343 if (m_num_wheel_diffs == 0)
1346 _L(
"No inter-wheel differential installed on current vehicle!"),
"error.png");
1350 String message =
"";
1351 for (
int i = 0; i < m_num_wheel_diffs; ++i)
1353 if (m_wheel_diffs[i])
1358 message +=
_L(
"Axle ") +
TOSTRING(i + 1) +
": ";
1359 message += m_wheel_diffs[i]->GetDifferentialTypeName();
1363 "Inter-wheel differentials:\n" + message,
"cog.png");
1367 void Actor::displayTransferCaseMode()
1369 if (m_transfer_case)
1372 _L(
"Transfercase switched to: ") + this->getTransferCaseName(),
"cog.png");
1377 _L(
"No transfercase installed on current vehicle!"),
"error.png");
1381 void Actor::toggleTransferCaseMode()
1383 if (!ar_engine || !m_transfer_case || m_transfer_case->tr_ax_2 < 0 || !m_transfer_case->tr_2wd)
1386 if (m_transfer_case->tr_4wd_mode && !m_transfer_case->tr_2wd_lo)
1388 for (
int i = 0; i < m_transfer_case->tr_gear_ratios.size(); i++)
1390 this->toggleTransferCaseGearRatio();
1391 if (m_transfer_case->tr_gear_ratios[0] == 1.0f)
1396 m_transfer_case->tr_4wd_mode = !m_transfer_case->tr_4wd_mode;
1398 if (m_transfer_case->tr_4wd_mode)
1400 ar_wheels[m_wheel_diffs[m_transfer_case->tr_ax_2]->di_idx_1].wh_propulsed =
true;
1401 ar_wheels[m_wheel_diffs[m_transfer_case->tr_ax_2]->di_idx_2].wh_propulsed =
true;
1402 m_num_proped_wheels += 2;
1406 ar_wheels[m_wheel_diffs[m_transfer_case->tr_ax_2]->di_idx_1].wh_propulsed =
false;
1407 ar_wheels[m_wheel_diffs[m_transfer_case->tr_ax_2]->di_idx_2].wh_propulsed =
false;
1408 m_num_proped_wheels -= 2;
1412 void Actor::toggleTransferCaseGearRatio()
1414 if (!ar_engine || !m_transfer_case || m_transfer_case->tr_gear_ratios.size() < 2)
1417 if (m_transfer_case->tr_4wd_mode || m_transfer_case->tr_2wd_lo)
1419 auto gear_ratios = &m_transfer_case->tr_gear_ratios;
1420 std::rotate(gear_ratios->begin(), gear_ratios->begin() + 1, gear_ratios->end());
1422 ar_engine->SetTCaseRatio(m_transfer_case->tr_gear_ratios[0]);
1426 String Actor::getTransferCaseName()
1429 if (m_transfer_case)
1431 name += m_transfer_case->tr_4wd_mode ?
"4WD " :
"2WD ";
1432 if (m_transfer_case->tr_gear_ratios[0] > 1.0f)
1433 name +=
"Lo (" +
TOSTRING(m_transfer_case->tr_gear_ratios[0]) +
":1)";
1440 Ogre::Vector3 Actor::getRotationCenter()
1442 Vector3 sum = Vector3::ZERO;
1443 std::vector<Vector3> positions;
1444 for (
int i = 0; i < ar_num_nodes; i++)
1446 Vector3 pos = ar_nodes[i].AbsPosition;
1447 const auto it = std::find_if(positions.begin(), positions.end(),
1448 [pos](
const Vector3 ref) { return pos.positionEquals(ref, 0.01f); });
1449 if (it == positions.end())
1452 positions.push_back(pos);
1455 return sum / positions.size();
1458 float Actor::getMinHeight(
bool skip_virtual_nodes)
1460 float height = std::numeric_limits<float>::max();
1461 for (
int i = 0; i < ar_num_nodes; i++)
1463 if (!skip_virtual_nodes || !ar_nodes[i].nd_no_ground_contact)
1465 height = std::min(ar_nodes[i].AbsPosition.y, height);
1468 return (!skip_virtual_nodes || height < std::numeric_limits<float>::max()) ? height : getMinHeight(
false);
1471 float Actor::getMaxHeight(
bool skip_virtual_nodes)
1473 float height = std::numeric_limits<float>::min();
1474 for (
int i = 0; i < ar_num_nodes; i++)
1476 if (!skip_virtual_nodes || !ar_nodes[i].nd_no_ground_contact)
1478 height = std::max(height, ar_nodes[i].AbsPosition.y);
1481 return (!skip_virtual_nodes || height > std::numeric_limits<float>::min()) ? height : getMaxHeight(
false);
1484 float Actor::getHeightAboveGround(
bool skip_virtual_nodes)
1486 float agl = std::numeric_limits<float>::max();
1487 for (
int i = 0; i < ar_num_nodes; i++)
1489 if (!skip_virtual_nodes || !ar_nodes[i].nd_no_ground_contact)
1491 Vector3 pos = ar_nodes[i].AbsPosition;
1495 return (!skip_virtual_nodes || agl < std::numeric_limits<float>::max()) ? agl : getHeightAboveGround(
false);
1498 float Actor::getHeightAboveGroundBelow(
float height,
bool skip_virtual_nodes)
1500 float agl = std::numeric_limits<float>::max();
1501 for (
int i = 0; i < ar_num_nodes; i++)
1503 if (!skip_virtual_nodes || !ar_nodes[i].nd_no_ground_contact)
1505 Vector3 pos = ar_nodes[i].AbsPosition;
1509 return (!skip_virtual_nodes || agl < std::numeric_limits<float>::max()) ? agl : getHeightAboveGroundBelow(height,
false);
1512 void Actor::reset(
bool keep_position)
1514 if (ar_state == ActorState::DISPOSED)
1519 rq->
amr_type = (keep_position) ? ActorModifyRequest::Type::RESET_ON_SPOT : ActorModifyRequest::Type::RESET_ON_INIT_POS;
1523 void Actor::SoftReset()
1527 float agl = this->getHeightAboveGroundBelow(this->getMaxHeight(
true),
true);
1531 agl = std::min(this->getMinHeight(
true) -
App::GetGameContext()->GetTerrain()->getWater()->GetStaticWaterHeight(), agl);
1536 Vector3 translation = -agl * Vector3::UNIT_Y;
1537 this->resetPosition(ar_nodes[0].AbsPosition + translation,
false);
1538 for (
ActorPtr& actor : ar_linked_actors)
1540 actor->resetPosition(actor->ar_nodes[0].AbsPosition + translation,
false);
1544 m_ongoing_reset =
true;
1547 void Actor::SyncReset(
bool reset_position)
1551 m_reset_timer.reset();
1553 m_camera_local_gforces_cur = Vector3::ZERO;
1554 m_camera_local_gforces_max = Vector3::ZERO;
1556 ar_hydro_dir_state = 0.0;
1557 ar_hydro_aileron_state = 0.0;
1558 ar_hydro_rudder_state = 0.0;
1559 ar_hydro_elevator_state = 0.0;
1560 ar_hydro_dir_wheel_display = 0.0;
1562 ar_fusedrag = Vector3::ZERO;
1564 ar_parking_brake =
false;
1565 ar_trailer_parking_brake =
false;
1566 ar_avg_wheel_speed = 0.0f;
1567 ar_wheel_speed = 0.0f;
1568 ar_wheel_spin = 0.0f;
1571 ar_origin = Vector3::ZERO;
1572 float cur_rot = getRotation();
1573 Vector3 cur_position = ar_nodes[0].AbsPosition;
1575 for (
int i = 0; i < ar_num_nodes; i++)
1577 ar_nodes[i].AbsPosition = ar_initial_node_positions[i];
1578 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1579 ar_nodes[i].Velocity = Vector3::ZERO;
1580 ar_nodes[i].Forces = Vector3::ZERO;
1583 for (
int i = 0; i < ar_num_beams; i++)
1585 ar_beams[i].maxposstress = ar_beams[i].default_beam_deform;
1586 ar_beams[i].maxnegstress = -ar_beams[i].default_beam_deform;
1587 ar_beams[i].minmaxposnegstress = ar_beams[i].default_beam_deform;
1588 ar_beams[i].strength = ar_beams[i].initial_beam_strength;
1589 ar_beams[i].L = ar_beams[i].refL;
1590 ar_beams[i].stress = 0.0;
1591 ar_beams[i].bm_broken =
false;
1592 ar_beams[i].bm_disabled =
false;
1595 this->applyNodeBeamScales();
1597 this->DisjoinInterActorBeams();
1599 for (
auto& h : ar_hooks)
1602 h.hk_lock_node =
nullptr;
1603 h.hk_locked_actor =
nullptr;
1604 h.hk_beam->p2 = &ar_nodes[0];
1605 h.hk_beam->bm_disabled =
true;
1606 h.hk_beam->bm_inter_actor =
false;
1607 h.hk_beam->L = (ar_nodes[0].AbsPosition - h.hk_hook_node->AbsPosition).length();
1608 this->RemoveInterActorBeam(h.hk_beam);
1611 for (
auto& r : ar_ropes)
1614 r.rp_locked_ropable =
nullptr;
1615 r.rp_locked_actor =
nullptr;
1616 this->RemoveInterActorBeam(r.rp_beam);
1619 for (
auto& t : ar_ties)
1623 t.ti_locked_actor =
nullptr;
1624 t.ti_locked_ropable =
nullptr;
1625 t.ti_beam->p2 = &ar_nodes[0];
1626 t.ti_beam->bm_disabled =
true;
1627 t.ti_beam->bm_inter_actor =
false;
1628 this->RemoveInterActorBeam(t.ti_beam);
1631 for (
auto& r : ar_ropables)
1633 r.attached_ties = 0;
1634 r.attached_ropes = 0;
1637 for (
int i = 0; i < ar_num_wheels; i++)
1639 ar_wheels[i].wh_speed = 0.0;
1640 ar_wheels[i].wh_torque = 0.0;
1641 ar_wheels[i].wh_avg_speed = 0.0;
1642 ar_wheels[i].wh_is_detached =
false;
1649 ar_engine->StartEngine();
1651 ar_engine->SetWheelSpin(0.0f);
1654 int num_axle_diffs = (m_transfer_case && m_transfer_case->tr_4wd_mode) ? m_num_axle_diffs + 1 : m_num_axle_diffs;
1655 for (
int i = 0; i < num_axle_diffs; i++)
1656 m_axle_diffs[i]->di_delta_rotation = 0.0f;
1657 for (
int i = 0; i < m_num_wheel_diffs; i++)
1658 m_wheel_diffs[i]->di_delta_rotation = 0.0f;
1659 for (
int i = 0; i < ar_num_aeroengines; i++)
1660 ar_aeroengines[i]->reset();
1661 for (
int i = 0; i < ar_num_screwprops; i++)
1662 ar_screwprops[i]->reset();
1663 for (
int i = 0; i < ar_num_rotators; i++)
1664 ar_rotators[i].angle = 0.0;
1665 for (
int i = 0; i < ar_num_wings; i++)
1666 ar_wings[i].fa->broken =
false;
1668 this->ar_autopilot->reset();
1670 m_buoyance->sink =
false;
1674 hydrobeam.hb_inertia.ResetCmdKeyDelay();
1677 this->GetGfxActor()->ResetFlexbodies();
1680 if (!reset_position)
1682 this->ResetAngle(cur_rot);
1683 this->resetPosition(cur_position,
false);
1684 float agl = this->getHeightAboveGroundBelow(this->getMaxHeight(
true),
true);
1687 agl = std::min(this->getMinHeight(
true) -
App::GetGameContext()->GetTerrain()->getWater()->GetStaticWaterHeight(), agl);
1691 this->resetPosition(ar_nodes[0].AbsPosition - agl * Vector3::UNIT_Y,
false);
1696 this->UpdateBoundingBoxes();
1697 this->calculateAveragePosition();
1702 ar_command_key[i].commandValue = 0.0;
1703 ar_command_key[i].triggerInputValue = 0.0f;
1704 ar_command_key[i].playerInputValue = 0.0f;
1705 for (
auto& b : ar_command_key[i].beams)
1707 b.cmb_state->auto_moving_mode = 0;
1708 b.cmb_state->pressed_center_mode =
false;
1712 this->resetSlideNodes();
1713 if (m_slidenodes_locked)
1715 this->toggleSlideNodeLock();
1718 m_ongoing_reset =
true;
1721 void Actor::applyNodeBeamScales()
1723 for (
int i = 0; i < ar_num_nodes; i++)
1725 ar_nodes[i].mass = ar_initial_node_masses[i] * ar_nb_mass_scale;
1728 m_total_mass = ar_initial_total_mass * ar_nb_mass_scale;
1730 for (
int i = 0; i < ar_num_beams; i++)
1732 if ((ar_beams[i].p1->nd_tyre_node || ar_beams[i].p1->nd_rim_node) ||
1733 (ar_beams[i].p2->nd_tyre_node || ar_beams[i].p2->nd_rim_node))
1735 ar_beams[i].k = ar_initial_beam_defaults[i].first * ar_nb_wheels_scale.first;
1736 ar_beams[i].d = ar_initial_beam_defaults[i].second * ar_nb_wheels_scale.second;
1738 else if (ar_beams[i].bounded ==
SHOCK1 || ar_beams[i].bounded ==
SHOCK2 || ar_beams[i].bounded ==
SHOCK3)
1740 ar_beams[i].k = ar_initial_beam_defaults[i].first * ar_nb_shocks_scale.first;;
1741 ar_beams[i].d = ar_initial_beam_defaults[i].second * ar_nb_shocks_scale.second;
1745 ar_beams[i].k = ar_initial_beam_defaults[i].first * ar_nb_beams_scale.first;
1746 ar_beams[i].d = ar_initial_beam_defaults[i].second * ar_nb_beams_scale.second;
1751 void Actor::ForceFeedbackStep(
int steps)
1753 m_force_sensors.out_body_forces = m_force_sensors.accu_body_forces / steps;
1754 if (!ar_hydros.empty())
1756 m_force_sensors.out_hydros_forces = (m_force_sensors.accu_hydros_forces / steps) / ar_hydros.size();
1760 void Actor::HandleAngelScriptEvents(
float dt)
1762 #ifdef USE_ANGELSCRIPT
1764 if (m_water_contact && !m_water_contact_old)
1766 m_water_contact_old = m_water_contact;
1769 #endif // USE_ANGELSCRIPT
1772 void Actor::searchBeamDefaults()
1776 auto old_beams_scale = ar_nb_beams_scale;
1777 auto old_shocks_scale = ar_nb_shocks_scale;
1778 auto old_wheels_scale = ar_nb_wheels_scale;
1780 if (ar_nb_initialized)
1782 ar_nb_beams_scale.first = Math::RangeRandom(ar_nb_beams_k_interval.first, ar_nb_beams_k_interval.second);
1783 ar_nb_beams_scale.second = Math::RangeRandom(ar_nb_beams_d_interval.first, ar_nb_beams_d_interval.second);
1784 ar_nb_shocks_scale.first = Math::RangeRandom(ar_nb_shocks_k_interval.first, ar_nb_shocks_k_interval.second);
1785 ar_nb_shocks_scale.second = Math::RangeRandom(ar_nb_shocks_d_interval.first, ar_nb_shocks_d_interval.second);
1786 ar_nb_wheels_scale.first = Math::RangeRandom(ar_nb_wheels_k_interval.first, ar_nb_wheels_k_interval.second);
1787 ar_nb_wheels_scale.second = Math::RangeRandom(ar_nb_wheels_d_interval.first, ar_nb_wheels_d_interval.second);
1791 ar_nb_beams_scale.first = Math::Clamp(1.0f, ar_nb_beams_k_interval.first, ar_nb_beams_k_interval.second);
1792 ar_nb_beams_scale.second = Math::Clamp(1.0f, ar_nb_beams_d_interval.first, ar_nb_beams_d_interval.second);
1793 ar_nb_shocks_scale.first = Math::Clamp(1.0f, ar_nb_shocks_k_interval.first, ar_nb_shocks_k_interval.second);
1794 ar_nb_shocks_scale.second = Math::Clamp(1.0f, ar_nb_shocks_d_interval.first, ar_nb_shocks_d_interval.second);
1795 ar_nb_wheels_scale.first = Math::Clamp(1.0f, ar_nb_wheels_k_interval.first, ar_nb_wheels_k_interval.second);
1796 ar_nb_wheels_scale.second = Math::Clamp(1.0f, ar_nb_wheels_d_interval.first, ar_nb_wheels_d_interval.second);
1797 ar_nb_reference = std::vector<float>(ar_nb_reference.size(), std::numeric_limits<float>::max());
1798 ar_nb_optimum = std::vector<float>(ar_nb_reference.size(), std::numeric_limits<float>::max());
1801 this->applyNodeBeamScales();
1803 m_ongoing_reset =
false;
1804 this->CalcForcesEulerPrepare(
true);
1805 for (
int i = 0; i < ar_nb_skip_steps; i++)
1807 this->CalcForcesEulerCompute(i == 0, ar_nb_skip_steps);
1808 if (m_ongoing_reset)
1811 m_ongoing_reset =
true;
1813 float sum_movement = 0.0f;
1814 float movement = 0.0f;
1815 float sum_velocity = 0.0f;
1816 float velocity = 0.0f;
1817 float sum_stress = 0.0f;
1818 float stress = 0.0f;
1820 for (
int k = 0; k < ar_nb_measure_steps; k++)
1822 this->CalcForcesEulerCompute(
false, ar_nb_measure_steps);
1823 for (
int i = 0; i < ar_num_nodes; i++)
1825 float v = ar_nodes[i].Velocity.length();
1826 sum_movement += v / (float)ar_nb_measure_steps;
1827 movement = std::max(movement, v);
1829 for (
int i = 0; i < ar_num_beams; i++)
1831 Vector3 dis = (ar_beams[i].p1->RelPosition - ar_beams[i].p2->RelPosition).normalisedCopy();
1832 float v = (ar_beams[i].p1->Velocity - ar_beams[i].p2->Velocity).dotProduct(dis);
1833 sum_velocity += std::abs(v) / (float)ar_nb_measure_steps;
1834 velocity = std::max(velocity, std::abs(v));
1835 sum_stress += std::abs(ar_beams[i].stress) / (float)ar_nb_measure_steps;
1836 stress = std::max(stress, std::abs(ar_beams[i].stress));
1837 if (k == 0 && ar_beams[i].bm_broken)
1842 if (sum_broken > ar_nb_reference[6] ||
1843 stress > ar_nb_reference[0] || velocity > ar_nb_reference[2] || movement > ar_nb_optimum[4] ||
1844 sum_stress > ar_nb_reference[1] || sum_velocity > ar_nb_reference[3] || sum_movement > ar_nb_optimum[5] * 2.f)
1846 ar_nb_beams_scale = old_beams_scale;
1847 ar_nb_shocks_scale = old_shocks_scale;
1848 ar_nb_wheels_scale = old_wheels_scale;
1855 ar_nb_optimum = {stress, sum_stress, velocity, sum_velocity, movement, sum_movement, (float)sum_broken};
1856 if (!ar_nb_initialized)
1858 ar_nb_reference = ar_nb_optimum;
1860 ar_nb_initialized =
true;
1863 void Actor::HandleInputEvents(
float dt)
1865 if (!m_ongoing_reset)
1868 if (m_anglesnap_request > 0)
1870 float rotation = Radian(getRotation()).valueDegrees();
1871 float target_rotation = std::round(rotation / m_anglesnap_request) * m_anglesnap_request;
1872 m_rotation_request = -Degree(target_rotation - rotation).valueRadians();
1873 m_rotation_request_center = getRotationCenter();
1874 m_anglesnap_request = 0;
1877 if (m_rotation_request != 0.0f)
1879 Quaternion rot = Quaternion(Radian(m_rotation_request), Vector3::UNIT_Y);
1881 for (
int i = 0; i < ar_num_nodes; i++)
1883 ar_nodes[i].AbsPosition -= m_rotation_request_center;
1884 ar_nodes[i].AbsPosition = rot * ar_nodes[i].AbsPosition;
1885 ar_nodes[i].AbsPosition += m_rotation_request_center;
1886 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1887 ar_nodes[i].Velocity = rot * ar_nodes[i].Velocity;
1888 ar_nodes[i].Forces = rot * ar_nodes[i].Forces;
1891 m_rotation_request = 0.0f;
1892 this->UpdateBoundingBoxes();
1893 calculateAveragePosition();
1896 if (m_translation_request != Vector3::ZERO)
1898 for (
int i = 0; i < ar_num_nodes; i++)
1900 ar_nodes[i].AbsPosition += m_translation_request;
1901 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1904 m_translation_request = Vector3::ZERO;
1905 UpdateBoundingBoxes();
1906 calculateAveragePosition();
1910 void Actor::sendStreamSetup()
1917 strncpy(reg.
name, ar_filename.c_str(), 128);
1918 if (m_used_skin_entry !=
nullptr)
1920 strncpy(reg.
skin, m_used_skin_entry->dname.c_str(), 60);
1926 #endif // USE_SOCKETW
1932 void Actor::sendStreamData()
1936 if (ar_net_timer.getMilliseconds() - ar_net_last_update_time < 100)
1939 ar_net_last_update_time = ar_net_timer.getMilliseconds();
1948 char send_buffer[8192] = {0};
1950 unsigned int packet_len = 0;
1967 if (ar_engine->hasContact())
1969 if (ar_engine->isRunning())
1972 switch (ar_engine->GetAutoShiftMode())
1986 if (ar_num_aeroengines > 0)
1988 float rpm = ar_aeroengines[0]->getRPM();
1993 send_oob->
brake = ar_brake;
1998 if (getCustomParticleMode())
2001 if (ar_parking_brake)
2003 if (m_tractioncontrol)
2005 if (m_antilockbrake)
2019 float* send_nodes = (
float *)ptr;
2020 packet_len += m_net_total_buffer_size;
2026 Vector3& refpos = ar_nodes[0].AbsPosition;
2027 send_nodes[0] = refpos.x;
2028 send_nodes[1] = refpos.y;
2029 send_nodes[2] = refpos.z;
2031 ptr +=
sizeof(float) * 3;
2034 short* sbuf = (
short*)ptr;
2035 for (i = 1; i < m_net_first_wheel_node; i++)
2037 Vector3 relpos = ar_nodes[i].AbsPosition - refpos;
2038 sbuf[(i - 1) * 3 + 0] = (
short int)(relpos.x * m_net_node_compression);
2039 sbuf[(i - 1) * 3 + 1] = (
short int)(relpos.y * m_net_node_compression);
2040 sbuf[(i - 1) * 3 + 2] = (
short int)(relpos.z * m_net_node_compression);
2042 ptr +=
sizeof(
short int) * 3;
2046 float* wfbuf = (
float*)ptr;
2047 for (i = 0; i < ar_num_wheels; i++)
2049 wfbuf[i] = ar_wheels[i].wh_net_rp;
2051 ptr += ar_num_wheels *
sizeof(float);
2054 for (
size_t i = 0; i < m_prop_anim_key_states.size(); i++)
2056 if (m_prop_anim_key_states[i].anim_active)
2059 char& dst_byte = *(ptr + (i / 8));
2060 char mask = ((char)m_prop_anim_key_states[i].anim_active) << (7 - (i % 8));
2070 void Actor::CalcAnimators(
hydrobeam_t const& hydrobeam,
float &cstate,
int &div)
2077 for (spi = 0; spi < ar_num_screwprops; spi++)
2078 if (ar_screwprops[spi])
2079 ctmp += ar_screwprops[spi]->getRudder();
2092 for (spi = 0; spi < ar_num_screwprops; spi++)
2093 if (ar_screwprops[spi])
2094 ctmp += ar_screwprops[spi]->getThrottle();
2105 if (m_num_wheel_diffs && m_wheel_diffs[0])
2107 String name = m_wheel_diffs[0]->GetDifferentialTypeName();
2110 if (name ==
"Split")
2112 if (name ==
"Locked")
2124 float heading = getRotation();
2126 cstate = (heading * 57.29578f) / 360.0f;
2133 float torque = ar_engine->GetCrankFactor();
2136 if (torque >= ar_anim_previous_crank)
2137 cstate -= torque / 10.0f;
2141 if (cstate <= -1.0f)
2143 ar_anim_previous_crank = torque;
2151 int shifter = ar_engine->GetGear();
2152 if (shifter > m_previous_gear)
2155 ar_anim_shift_timer = 0.2f;
2157 if (shifter < m_previous_gear)
2160 ar_anim_shift_timer = -0.2f;
2162 m_previous_gear = shifter;
2164 if (ar_anim_shift_timer > 0.0f)
2168 if (ar_anim_shift_timer < 0.0f)
2169 ar_anim_shift_timer = 0.0f;
2171 if (ar_anim_shift_timer < 0.0f)
2175 if (ar_anim_shift_timer > 0.0f)
2176 ar_anim_shift_timer = 0.0f;
2185 int shifter = ar_engine->GetGear();
2190 else if (shifter < 0)
2196 cstate -= int((shifter - 1.0) / 2.0);
2204 int shifter = ar_engine->GetGear();
2212 cstate = shifter % 2;
2220 int shifter = ar_engine->GetGear();
2221 int numgears = ar_engine->getNumGears();
2222 cstate -= (shifter + 2.0) / (numgears + 2.0);
2229 float pbrake = ar_parking_brake;
2237 float speedo = ar_wheel_speed / ar_guisettings_speedo_max_kph;
2238 cstate -= speedo * 3.0f;
2245 float tacho = ar_engine->GetEngineRpm() / ar_engine->getMaxRPM();
2253 float turbo = ar_engine->GetTurboPsi() * 3.34;
2254 cstate -= turbo / 67.0f;
2268 float accel = ar_engine->GetAcceleration();
2269 cstate -= accel + 0.06f;
2277 float clutch = ar_engine->GetClutch();
2278 cstate -= fabs(1.0f - clutch);
2289 float pcent = ar_aeroengines[aenum]->getRPMpc();
2291 angle = -5.0 + pcent * 1.9167;
2292 else if (pcent < 110.0)
2293 angle = 110.0 + (pcent - 60.0) * 4.075;
2296 cstate -= angle / 314.0f;
2301 float throttle = ar_aeroengines[aenum]->getThrottle();
2307 if (ar_aeroengines[aenum]->getType() == AeroEngineType::AE_XPROP)
2315 if (ar_aeroengines[aenum]->getType() == AeroEngineType::AE_XPROP)
2318 cstate = tp->
pitch / 120.0f;
2324 if (!ar_aeroengines[aenum]->getIgnition())
2328 if (ar_aeroengines[aenum]->isFailed())
2337 float ground_speed_kt = ar_nodes[0].Velocity.length() * 1.9438;
2338 float altitude = ar_nodes[0].AbsPosition.y;
2339 float sea_level_pressure = 101325;
2340 float airpressure = sea_level_pressure * pow(1.0 - 0.0065 * altitude / 288.15, 5.24947);
2341 float airdensity = airpressure * 0.0000120896;
2342 float kt = ground_speed_kt * sqrt(airdensity / 1.225);
2343 cstate -= kt / 100.0f;
2350 float vvi = ar_nodes[0].Velocity.y * 196.85;
2352 cstate -= vvi / 6000.0f;
2355 if (cstate <= -1.0f)
2366 float altimeter = (ar_nodes[0].AbsPosition.y * 1.1811) / 360.0f;
2367 int alti_int = int(altimeter);
2368 float alti_mod = (altimeter - alti_int);
2375 float alti = ar_nodes[0].AbsPosition.y * 1.1811 / 3600.0f;
2376 int alti_int = int(alti);
2377 float alti_mod = (alti - alti_int);
2379 if (cstate <= -1.0f)
2386 float alti = ar_nodes[0].AbsPosition.y * 1.1811 / 36000.0f;
2388 if (cstate <= -1.0f)
2398 if (ar_num_wings > 4)
2399 aoa = (ar_wings[4].fa->aoa) / 25.0f;
2400 if ((ar_nodes[0].Velocity.length() * 1.9438) < 10.0f)
2403 if (cstate <= -1.0f)
2413 Vector3 rollv = this->GetCameraRoll();
2414 Vector3 dirv = this->GetCameraDir();
2415 Vector3 upv = dirv.crossProduct(-rollv);
2416 float rollangle = asin(rollv.dotProduct(Vector3::UNIT_Y));
2418 rollangle = Math::RadiansToDegrees(rollangle);
2421 rollangle = 180.0f - rollangle;
2422 cstate = rollangle / 180.0f;
2426 cstate = cstate - 2.0f;
2433 Vector3 dirv = this->GetCameraDir();
2434 float pitchangle = asin(dirv.dotProduct(Vector3::UNIT_Y));
2436 cstate = (Math::RadiansToDegrees(pitchangle) / 90.0f);
2443 float airbrake = ar_airbrake_intensity;
2445 cstate -= airbrake / 5.0f;
2459 void Actor::CalcCabCollisions()
2461 for (
int i = 0; i < ar_num_nodes; i++)
2463 ar_nodes[i].nd_has_mesh_contact =
false;
2465 if (m_intra_point_col_detector !=
nullptr)
2467 m_intra_point_col_detector->UpdateIntraPoint();
2469 *m_intra_point_col_detector,
2473 ar_intra_collcabrate,
2476 *ar_submesh_ground_model);
2480 void Actor::CalcShocks2(
int i, Real difftoBeamL, Real& k, Real& d, Real v)
2484 k = ar_beams[i].shock->springout;
2485 d = ar_beams[i].shock->dampout;
2487 float logafactor = 1.0f;
2488 if (ar_beams[i].longbound != 0.0f)
2490 logafactor = difftoBeamL / (ar_beams[i].longbound * ar_beams[i].L);
2491 logafactor = std::min(logafactor * logafactor, 1.0f);
2493 k += ar_beams[i].shock->sprogout * k * logafactor;
2494 d += ar_beams[i].shock->dprogout * d * logafactor;
2498 k = ar_beams[i].shock->springin;
2499 d = ar_beams[i].shock->dampin;
2501 float logafactor = 1.0f;
2502 if (ar_beams[i].shortbound != 0.0f)
2504 logafactor = difftoBeamL / (ar_beams[i].shortbound * ar_beams[i].L);
2505 logafactor = std::min(logafactor * logafactor, 1.0f);
2507 k += ar_beams[i].shock->sprogin * k * logafactor;
2508 d += ar_beams[i].shock->dprogin * d * logafactor;
2513 float beamsLep = ar_beams[i].L * 0.8f;
2514 float longboundprelimit = ar_beams[i].longbound * beamsLep;
2515 float shortboundprelimit = -ar_beams[i].shortbound * beamsLep;
2516 if (difftoBeamL > longboundprelimit)
2519 k = ar_beams[i].shock->springout;
2520 d = ar_beams[i].shock->dampout;
2522 float logafactor = 1.0f;
2523 if (ar_beams[i].longbound != 0.0f)
2525 logafactor = difftoBeamL / (ar_beams[i].longbound * ar_beams[i].L);
2526 logafactor = std::min(logafactor * logafactor, 1.0f);
2528 k += ar_beams[i].shock->sprogout * k * logafactor;
2529 d += ar_beams[i].shock->dprogout * d * logafactor;
2532 if (ar_beams[i].longbound != 0.0f)
2534 logafactor = ((difftoBeamL - longboundprelimit) * 5.0f) / (ar_beams[i].longbound * ar_beams[i].L);
2535 logafactor = std::min(logafactor * logafactor, 1.0f);
2537 k += (k + 100.0f) * ar_beams[i].shock->sprogout * logafactor;
2538 d += (d + 100.0f) * ar_beams[i].shock->dprogout * logafactor;
2542 k = ar_beams[i].shock->springin;
2543 d = ar_beams[i].shock->dampin;
2546 else if (difftoBeamL < shortboundprelimit)
2549 k = ar_beams[i].shock->springin;
2550 d = ar_beams[i].shock->dampin;
2552 float logafactor = 1.0f;
2553 if (ar_beams[i].shortbound != 0.0f)
2555 logafactor = difftoBeamL / (ar_beams[i].shortbound * ar_beams[i].L);
2556 logafactor = std::min(logafactor * logafactor, 1.0f);
2558 k += ar_beams[i].shock->sprogin * k * logafactor;
2559 d += ar_beams[i].shock->dprogin * d * logafactor;
2562 if (ar_beams[i].shortbound != 0.0f)
2564 logafactor = ((difftoBeamL - shortboundprelimit) * 5.0f) / (ar_beams[i].shortbound * ar_beams[i].L);
2565 logafactor = std::min(logafactor * logafactor, 1.0f);
2567 k += (k + 100.0f) * ar_beams[i].shock->sprogout * logafactor;
2568 d += (d + 100.0f) * ar_beams[i].shock->dprogout * logafactor;
2572 k = ar_beams[i].shock->springout;
2573 d = ar_beams[i].shock->dampout;
2576 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L || difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
2579 k = std::max(k, ar_beams[i].shock->sbd_spring);
2580 d = std::max(d, ar_beams[i].shock->sbd_damp);
2583 else if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L || difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
2586 k = ar_beams[i].shock->sbd_spring;
2587 d = ar_beams[i].shock->sbd_damp;
2591 void Actor::CalcShocks3(
int i, Real difftoBeamL, Real &k, Real& d, Real v)
2593 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L)
2595 float interp_ratio = difftoBeamL - ar_beams[i].longbound * ar_beams[i].L;
2596 k += (ar_beams[i].shock->sbd_spring - k) * interp_ratio;
2597 d += (ar_beams[i].shock->sbd_damp - d) * interp_ratio;
2599 else if (difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
2601 float interp_ratio = -difftoBeamL - ar_beams[i].shortbound * ar_beams[i].L;
2602 k += (ar_beams[i].shock->sbd_spring - k) * interp_ratio;
2603 d += (ar_beams[i].shock->sbd_damp - d) * interp_ratio;
2607 v = Math::Clamp(std::abs(v), +0.15f, +20.0f);
2608 k = ar_beams[i].shock->springout;
2609 d = ar_beams[i].shock->dampout * ar_beams[i].shock->dslowout * std::min(v, ar_beams[i].shock->splitout) +
2610 ar_beams[i].shock->dampout * ar_beams[i].shock->dfastout * std::max(0.0f, v - ar_beams[i].shock->splitout);
2615 v = Math::Clamp(std::abs(v), +0.15f, +20.0f);
2616 k = ar_beams[i].shock->springin;
2617 d = ar_beams[i].shock->dampin * ar_beams[i].shock->dslowin * std::min(v, ar_beams[i].shock->splitin ) +
2618 ar_beams[i].shock->dampin * ar_beams[i].shock->dfastin * std::max(0.0f, v - ar_beams[i].shock->splitin );
2623 void Actor::CalcTriggers(
int i, Real difftoBeamL,
bool trigger_hooks)
2629 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L || difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
2631 ar_beams[i].shock->trigger_switch_state -= dt;
2632 if (ar_beams[i].shock->trigger_switch_state <= 0.0f)
2633 ar_beams[i].shock->trigger_switch_state = 0.0f;
2636 for (
int scount = i + 1; scount <= i + ar_beams[i].shock->trigger_cmdshort; scount++)
2640 if (m_trigger_debug_enabled && !ar_beams[scount].shock->trigger_enabled && ar_beams[i].shock->last_debug_state != 1)
2642 LOG(
" Trigger disabled. Blocker BeamID " +
TOSTRING(i) +
" enabled trigger " +
TOSTRING(scount));
2643 ar_beams[i].shock->last_debug_state = 1;
2645 ar_beams[scount].shock->trigger_enabled =
false;
2651 for (
int scount = i + 1; scount <= i + ar_beams[i].shock->trigger_cmdlong; scount++)
2655 if (m_trigger_debug_enabled && ar_beams[scount].shock->trigger_enabled && ar_beams[i].shock->last_debug_state != 9)
2657 LOG(
" Trigger enabled. Inverted Blocker BeamID " +
TOSTRING(i) +
" disabled trigger " +
TOSTRING(scount));
2658 ar_beams[i].shock->last_debug_state = 9;
2660 ar_beams[scount].shock->trigger_enabled =
true;
2666 ar_command_key[ar_beams[i].shock->trigger_cmdshort].trigger_cmdkeyblock_state =
false;
2667 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 2)
2669 LOG(
" F-key trigger block released. Blocker BeamID " +
TOSTRING(i) +
" Released F" +
TOSTRING(ar_beams[i].shock->trigger_cmdshort));
2670 ar_beams[i].shock->last_debug_state = 2;
2675 if (!ar_beams[i].shock->trigger_switch_state)
2677 for (
int scount = 0; scount < ar_num_shocks; scount++)
2679 int short1 = ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdshort;
2680 int short2 = ar_beams[i].shock->trigger_cmdshort;
2681 int long1 = ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdlong;
2682 int long2 = ar_beams[i].shock->trigger_cmdlong;
2683 int tmpi = ar_beams[ar_shocks[scount].beamid].shock->beamid;
2684 if (((short1 == short2 && long1 == long2) || (short1 == long2 && long1 == short2)) && i != tmpi)
2686 int tmpcmdkey = ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdlong;
2687 ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdlong = ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdshort;
2688 ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdshort = tmpcmdkey;
2689 ar_beams[i].shock->trigger_switch_state = ar_beams[i].shock->trigger_boundary_t;
2690 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 3)
2692 LOG(
" Trigger F-key commands switched. Switch BeamID " +
TOSTRING(i)+
" switched commands of Trigger BeamID " +
TOSTRING(ar_beams[ar_shocks[scount].beamid].shock->beamid) +
" to cmdShort: F" +
TOSTRING(ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdshort) +
", cmdlong: F" +
TOSTRING(ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdlong));
2693 ar_beams[i].shock->last_debug_state = 3;
2701 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L)
2710 rq->
alr_type = ActorLinkingRequestType::HOOK_ACTION;
2724 rq->
alr_type = ActorLinkingRequestType::HOOK_ACTION;
2733 engineTriggerHelper(ar_beams[i].shock->trigger_cmdshort,
EngineTriggerType(ar_beams[i].shock->trigger_cmdlong), 1.0f);
2738 if (!ar_command_key[ar_beams[i].shock->trigger_cmdlong].trigger_cmdkeyblock_state)
2741 ar_command_key[ar_beams[i].shock->trigger_cmdshort].triggerInputValue = 1;
2743 ar_command_key[ar_beams[i].shock->trigger_cmdlong].triggerInputValue = 1;
2744 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 4)
2746 LOG(
" Trigger Longbound activated. Trigger BeamID " +
TOSTRING(i) +
" Triggered F" +
TOSTRING(ar_beams[i].shock->trigger_cmdlong));
2747 ar_beams[i].shock->last_debug_state = 4;
2761 rq->
alr_type = ActorLinkingRequestType::HOOK_ACTION;
2775 rq->
alr_type = ActorLinkingRequestType::HOOK_ACTION;
2786 engineTriggerHelper(ar_beams[i].shock->trigger_cmdshort,
EngineTriggerType(ar_beams[i].shock->trigger_cmdlong), triggerValue);
2791 if (!ar_command_key[ar_beams[i].shock->trigger_cmdshort].trigger_cmdkeyblock_state)
2794 ar_command_key[ar_beams[i].shock->trigger_cmdshort].triggerInputValue = 0;
2796 ar_command_key[ar_beams[i].shock->trigger_cmdshort].triggerInputValue = 1;
2798 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 5)
2800 LOG(
" Trigger Shortbound activated. Trigger BeamID " +
TOSTRING(i) +
" Triggered F" +
TOSTRING(ar_beams[i].shock->trigger_cmdshort));
2801 ar_beams[i].shock->last_debug_state = 5;
2812 if (ar_beams[i].longbound - ar_beams[i].shortbound > 0.0f)
2814 float diffPercentage = difftoBeamL / ar_beams[i].L;
2815 float triggerValue = (diffPercentage - ar_beams[i].shortbound) / (ar_beams[i].longbound - ar_beams[i].shortbound);
2817 triggerValue = std::max(0.0f, triggerValue);
2818 triggerValue = std::min(triggerValue, 1.0f);
2822 engineTriggerHelper(ar_beams[i].shock->trigger_cmdshort,
EngineTriggerType(ar_beams[i].shock->trigger_cmdlong), triggerValue);
2827 ar_command_key[ar_beams[i].shock->trigger_cmdshort].triggerInputValue = triggerValue;
2828 ar_command_key[ar_beams[i].shock->trigger_cmdlong].triggerInputValue = triggerValue;
2834 for (
int scount = i + 1; scount <= i + ar_beams[i].shock->trigger_cmdlong; scount++)
2838 if (m_trigger_debug_enabled && ar_beams[scount].shock->trigger_enabled && ar_beams[i].shock->last_debug_state != 6)
2840 LOG(
" Trigger enabled. Blocker BeamID " +
TOSTRING(i) +
" disabled trigger " +
TOSTRING(scount));
2841 ar_beams[i].shock->last_debug_state = 6;
2843 ar_beams[scount].shock->trigger_enabled =
true;
2849 for (
int scount = i + 1; scount <= i + ar_beams[i].shock->trigger_cmdshort; scount++)
2853 if (m_trigger_debug_enabled && !ar_beams[scount].shock->trigger_enabled && ar_beams[i].shock->last_debug_state != 10)
2855 LOG(
" Trigger disabled. Inverted Blocker BeamID " +
TOSTRING(i) +
" enabled trigger " +
TOSTRING(scount));
2856 ar_beams[i].shock->last_debug_state = 10;
2858 ar_beams[scount].shock->trigger_enabled =
false;
2864 ar_beams[i].shock->trigger_switch_state = 0.0f;
2865 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 7)
2867 LOG(
" Trigger switch reset. Switch BeamID " +
TOSTRING(i));
2868 ar_beams[i].shock->last_debug_state = 7;
2871 else if ((ar_beams[i].shock->flags &
SHOCK_FLAG_TRG_CMD_BLOCKER) && !ar_command_key[ar_beams[i].shock->trigger_cmdshort].trigger_cmdkeyblock_state)
2873 ar_command_key[ar_beams[i].shock->trigger_cmdshort].trigger_cmdkeyblock_state =
true;
2874 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 8)
2876 LOG(
" F-key trigger blocked. Blocker BeamID " +
TOSTRING(i) +
" Blocked F" +
TOSTRING(ar_beams[i].shock->trigger_cmdshort));
2877 ar_beams[i].shock->last_debug_state = 8;
2884 void Actor::setAirbrakeIntensity(
float intensity)
2886 ar_airbrake_intensity = intensity;
2889 ab->updatePosition((
float)ar_airbrake_intensity / 5.0);
2894 void Actor::updateSkidmarks()
2896 for (
int i = 0; i < ar_num_wheels; i++)
2898 if (!m_skid_trails[i])
2901 for (
int j = 0; j < ar_wheels[i].wh_num_nodes; j++)
2903 auto n = ar_wheels[i].wh_nodes[j];
2904 if (!n || !n->nd_has_ground_contact || n->nd_last_collision_gm ==
nullptr ||
2905 n->nd_last_collision_gm->fx_type != Collisions::FX_HARD)
2909 if (n->nd_avg_collision_slip > 6.f && n->nd_last_collision_slip.squaredLength() > 9.f)
2911 m_skid_trails[i]->update(n->AbsPosition, j, n->nd_avg_collision_slip, n->nd_last_collision_gm->name);
2918 void Actor::prepareInside(
bool inside)
2926 MaterialPtr seatmat = (MaterialPtr)(MaterialManager::getSingleton().getByName(
"driversseat"));
2927 seatmat->setDepthWriteEnabled(
false);
2928 seatmat->setSceneBlending(SBT_TRANSPARENT_ALPHA);
2934 ar_dashboard->setVisible(
false);
2940 MaterialPtr seatmat = (MaterialPtr)(MaterialManager::getSingleton().getByName(
"driversseat"));
2941 seatmat->setDepthWriteEnabled(
true);
2942 seatmat->setSceneBlending(SBT_REPLACE);
2953 m_gfx_actor->SetCastShadows(!inside);
2957 void Actor::toggleHeadlights()
2961 if (ar_state == ActorState::LOCAL_SIMULATED &&
this == player_actor.
GetRef() && ar_forward_commands)
2965 if (actor->ar_state == ActorState::LOCAL_SIMULATED &&
this != actor.GetRef() && actor->ar_import_commands)
2974 m_gfx_actor->SetCabLightsActive(this->getHeadlightsVisible());
2979 void Actor::forceAllFlaresOff()
2981 for (
size_t i = 0; i < ar_flares.size(); i++)
2983 ar_flares[i].snode->setVisible(
false);
2987 void Actor::updateFlareStates(
float dt)
2989 if (m_flares_mode == GfxFlaresMode::NONE) {
return; }
2991 for (
size_t i = 0; i < this->ar_flares.size(); i++)
2994 if (ar_flares[i].blinkdelay != 0)
2996 ar_flares[i].blinkdelay_curr -= dt;
2997 if (ar_flares[i].blinkdelay_curr <= 0)
2999 ar_flares[i].blinkdelay_curr = ar_flares[i].blinkdelay;
3000 ar_flares[i].blinkdelay_state = !ar_flares[i].blinkdelay_state;
3005 ar_flares[i].blinkdelay_state =
true;
3009 bool isvisible =
false;
3010 switch (ar_flares[i].fl_type)
3021 case FlareType::DASHBOARD: isvisible = ar_dashboard->_getBool(ar_flares[i].dashboard_link);
break;
3022 case FlareType::USER: isvisible = this->getCustomLightVisible(ar_flares[i].controlnumber);
break;
3026 isvisible = isvisible && ar_flares[i].blinkdelay_state;
3029 switch (ar_flares[i].fl_type)
3031 case FlareType::BLINKER_LEFT: m_blinker_left_lit = isvisible;
break;
3032 case FlareType::BLINKER_RIGHT: m_blinker_right_lit = isvisible;
break;
3037 if (ar_flares[i].uses_inertia)
3039 ar_flares[i].intensity = ar_flares[i].inertia.CalcSimpleDelay(isvisible, dt);
3043 ar_flares[i].intensity = (float)isvisible;
3050 if (this->getBlinkType() == blink)
3053 setBlinkType(blink);
3058 if (ar_state == ActorState::DISPOSED)
3090 void Actor::autoBlinkReset()
3095 if (this->getBlinkType() ==
BLINK_LEFT && ar_hydro_dir_state < -blink_lock_range)
3098 m_blinker_autoreset =
true;
3101 if (this->getBlinkType() ==
BLINK_LEFT && m_blinker_autoreset && ar_hydro_dir_state > -blink_lock_range)
3105 m_blinker_autoreset =
false;
3109 if (this->getBlinkType() ==
BLINK_RIGHT && ar_hydro_dir_state > blink_lock_range)
3110 m_blinker_autoreset =
true;
3112 if (this->getBlinkType() ==
BLINK_RIGHT && m_blinker_autoreset && ar_hydro_dir_state < blink_lock_range)
3115 m_blinker_autoreset =
false;
3125 this->toggleHeadlights();
3127 this->beaconsToggle();
3136 this->setBlinkType(btype);
3139 m_lightmask = lightmask;
3142 void Actor::toggleCustomParticles()
3144 if (ar_state == ActorState::DISPOSED)
3147 m_custom_particles_enabled = !m_custom_particles_enabled;
3148 for (
int i = 0; i < ar_num_custom_particles; i++)
3150 ar_custom_particles[i].active = !ar_custom_particles[i].active;
3151 for (
int j = 0; j < ar_custom_particles[i].psys->getNumEmitters(); j++)
3153 ar_custom_particles[i].psys->getEmitter(j)->setEnabled(ar_custom_particles[i].active);
3161 void Actor::updateSoundSources()
3166 for (
int i = 0; i < ar_num_soundsources; i++)
3169 ar_soundsources[i].ssi->setPosition(ar_nodes[ar_soundsources[i].nodenum].AbsPosition);
3170 ar_soundsources[i].ssi->setVelocity(ar_nodes[ar_soundsources[i].nodenum].Velocity);
3178 void Actor::updateVisual(
float dt)
3180 Vector3 ref(Vector3::UNIT_Y);
3182 updateSoundSources();
3186 if (ar_driveable ==
AIRPLANE && ar_state != ActorState::LOCAL_SLEEPING)
3189 m_avionic_chatter_timer -= dt;
3190 if (m_avionic_chatter_timer < 0)
3193 m_avionic_chatter_timer = Math::RangeRandom(11, 30);
3200 if (ar_engine && exhausts.size() > 0)
3202 std::vector<exhaust_t>::iterator it;
3203 for (it = exhausts.begin(); it != exhausts.end(); it++)
3207 Vector3 dir = ar_nodes[it->emitterNode].AbsPosition - ar_nodes[it->directionNode].AbsPosition;
3209 ParticleEmitter* emit = it->smoker->getEmitter(0);
3210 it->smokeNode->setPosition(ar_nodes[it->emitterNode].AbsPosition);
3211 emit->setDirection(dir);
3212 if (!m_disable_smoke && ar_engine->GetSmoke() != -1.0)
3214 emit->setEnabled(
true);
3215 emit->setColour(ColourValue(0.0, 0.0, 0.0, 0.02 + ar_engine->GetSmoke() * 0.06));
3216 emit->setTimeToLive((0.02 + ar_engine->GetSmoke() * 0.06) / 0.04);
3220 emit->setEnabled(
false);
3222 emit->setParticleVelocity(1.0 + ar_engine->GetSmoke() * 2.0, 2.0 + ar_engine->GetSmoke() * 3.0);
3227 float autoaileron = 0;
3228 float autorudder = 0;
3229 float autoelevator = 0;
3232 ar_autopilot->UpdateIls(
App::GetGameContext()->GetTerrain()->getObjectManager()->GetLocalizers());
3233 autoaileron = ar_autopilot->getAilerons();
3234 autorudder = ar_autopilot->getRudder();
3235 autoelevator = ar_autopilot->getElevator();
3236 ar_autopilot->gpws_update(ar_posnode_spawn_height);
3238 autoaileron += ar_aileron;
3239 autorudder += ar_rudder;
3240 autoelevator += ar_elevator;
3241 if (autoaileron < -1.0)
3243 if (autoaileron > 1.0)
3245 if (autorudder < -1.0)
3247 if (autorudder > 1.0)
3249 if (autoelevator < -1.0)
3250 autoelevator = -1.0;
3251 if (autoelevator > 1.0)
3253 for (
int i = 0; i < ar_num_wings; i++)
3255 if (ar_wings[i].fa->type ==
'a')
3256 ar_wings[i].fa->setControlDeflection(autoaileron);
3257 if (ar_wings[i].fa->type ==
'b')
3258 ar_wings[i].fa->setControlDeflection(-autoaileron);
3259 if (ar_wings[i].fa->type ==
'r')
3260 ar_wings[i].fa->setControlDeflection(autorudder);
3261 if (ar_wings[i].fa->type ==
'e' || ar_wings[i].fa->type ==
'S' || ar_wings[i].fa->type ==
'T')
3262 ar_wings[i].fa->setControlDeflection(autoelevator);
3263 if (ar_wings[i].fa->type ==
'f')
3264 ar_wings[i].fa->setControlDeflection(
FLAP_ANGLES[ar_aerial_flap]);
3265 if (ar_wings[i].fa->type ==
'c' || ar_wings[i].fa->type ==
'V')
3266 ar_wings[i].fa->setControlDeflection((autoaileron + autoelevator) / 2.0);
3267 if (ar_wings[i].fa->type ==
'd' || ar_wings[i].fa->type ==
'U')
3268 ar_wings[i].fa->setControlDeflection((-autoaileron + autoelevator) / 2.0);
3269 if (ar_wings[i].fa->type ==
'g')
3270 ar_wings[i].fa->setControlDeflection((autoaileron +
FLAP_ANGLES[ar_aerial_flap]) / 2.0);
3271 if (ar_wings[i].fa->type ==
'h')
3272 ar_wings[i].fa->setControlDeflection((-autoaileron +
FLAP_ANGLES[ar_aerial_flap]) / 2.0);
3273 if (ar_wings[i].fa->type ==
'i')
3274 ar_wings[i].fa->setControlDeflection((-autoelevator + autorudder) / 2.0);
3275 if (ar_wings[i].fa->type ==
'j')
3276 ar_wings[i].fa->setControlDeflection((autoelevator + autorudder) / 2.0);
3277 ar_wings[i].fa->updateVerticesPhysics();
3280 ar_hydro_aileron_command = autoaileron;
3281 ar_hydro_rudder_command = autorudder;
3282 ar_hydro_elevator_command = autoelevator;
3289 auto pos = std::find(ar_inter_beams.begin(), ar_inter_beams.end(), beam);
3290 if (pos == ar_inter_beams.end())
3292 ar_inter_beams.push_back(beam);
3295 std::pair<ActorPtr, ActorPtr> actor_pair(a, b);
3307 void Actor::RemoveInterActorBeam(
beam_t* beam)
3309 auto pos = std::find(ar_inter_beams.begin(), ar_inter_beams.end(), beam);
3310 if (pos != ar_inter_beams.end())
3312 ar_inter_beams.erase(pos);
3318 auto actor_pair = it->second;
3321 actor_pair.first->DetermineLinkedActors();
3325 actor_pair.second->DetermineLinkedActors();
3331 void Actor::DisjoinInterActorBeams()
3333 ar_inter_beams.clear();
3335 for (
auto it = inter_actor_links->begin(); it != inter_actor_links->end();)
3337 auto actor_pair = it->second;
3338 if (
this == actor_pair.first.GetRef() ||
this == actor_pair.second.GetRef())
3340 it->first->bm_locked_actor =
nullptr;
3341 it->first->bm_inter_actor =
false;
3342 it->first->bm_disabled =
true;
3343 inter_actor_links->erase(it++);
3345 actor_pair.first->DetermineLinkedActors();
3349 actor_pair.second->DetermineLinkedActors();
3360 void Actor::tieToggle(
int group)
3365 bool istied =
false;
3367 for (std::vector<tie_t>::iterator it = ar_ties.begin(); it != ar_ties.end(); it++)
3370 if (group != -1 && (it->ti_group != -1 && it->ti_group != group))
3376 istied = !it->ti_beam->bm_disabled;
3379 it->ti_tied =
false;
3380 it->ti_tying =
false;
3381 if (it->ti_locked_ropable)
3382 it->ti_locked_ropable->attached_ties--;
3384 it->ti_beam->p2 = &ar_nodes[0];
3385 it->ti_beam->bm_inter_actor =
false;
3386 it->ti_beam->bm_disabled =
true;
3387 if (it->ti_locked_actor !=
this)
3389 this->RemoveInterActorBeam(it->ti_beam);
3392 it->ti_locked_actor =
nullptr;
3399 for (std::vector<tie_t>::iterator it = ar_ties.begin(); it != ar_ties.end(); it++)
3402 if (group != -1 && (it->ti_group != -1 && it->ti_group != group))
3408 float mindist = it->ti_beam->refL;
3409 node_t* nearest_node = 0;
3415 if (actor->ar_state == ActorState::LOCAL_SLEEPING ||
3416 (actor ==
this && it->ti_no_self_lock))
3422 for (std::vector<ropable_t>::iterator itr = actor->ar_ropables.begin(); itr != actor->ar_ropables.end(); itr++)
3425 if (!itr->multilock && itr->attached_ties > 0)
3429 if (
this == actor.GetRef() && itr->node->pos == it->ti_beam->p1->pos)
3433 float dist = (it->ti_beam->p1->AbsPosition - itr->node->AbsPosition).length();
3437 nearest_node = itr->node;
3438 nearest_actor = actor;
3439 locktedto = &(*itr);
3447 it->ti_beam->bm_disabled =
false;
3449 it->ti_locked_actor = nearest_actor;
3450 it->ti_beam->p2 = nearest_node;
3451 it->ti_beam->bm_inter_actor = nearest_actor !=
this;
3452 it->ti_beam->stress = 0;
3453 it->ti_beam->L = it->ti_beam->refL;
3455 it->ti_tying =
true;
3456 it->ti_locked_ropable = locktedto;
3458 if (it->ti_beam->bm_inter_actor)
3460 AddInterActorBeam(it->ti_beam,
this, nearest_actor);
3472 void Actor::ropeToggle(
int group)
3477 for (std::vector<rope_t>::iterator it = ar_ropes.begin(); it != ar_ropes.end(); it++)
3480 if (group != -1 && (it->rp_group != -1 && it->rp_group != group))
3488 if (it->rp_locked_ropable)
3489 it->rp_locked_ropable->attached_ropes--;
3490 if (it->rp_locked_actor !=
this)
3492 this->RemoveInterActorBeam(it->rp_beam);
3495 it->rp_locked_actor =
nullptr;
3496 it->rp_locked_ropable =
nullptr;
3502 float mindist = it->rp_beam->L;
3508 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
3511 for (std::vector<ropable_t>::iterator itr = actor->ar_ropables.begin(); itr != actor->ar_ropables.end(); itr++)
3514 if (!itr->multilock && itr->attached_ropes > 0)
3518 float dist = (it->rp_beam->p1->AbsPosition - itr->node->AbsPosition).length();
3522 nearest_actor = actor;
3531 it->rp_locked_actor = nearest_actor;
3533 it->rp_locked_ropable = rop;
3535 if (nearest_actor !=
this)
3537 AddInterActorBeam(it->rp_beam,
this, nearest_actor);
3548 for (std::vector<hook_t>::iterator it = ar_hooks.begin(); it != ar_hooks.end(); it++)
3558 if (it->hk_group <= -2)
3564 if (it->hk_group >= -1 || !it->hk_autolock)
3570 if (it->hk_group >= -1 || !it->hk_autolock)
3576 if (it->hk_group != group)
3583 if (mode ==
HOOK_LOCK && it->hk_timer > 0.0f)
3589 ActorPtr prev_locked_actor = it->hk_locked_actor;
3596 float mindist = it->hk_lockrange;
3597 float distance = 100000000.0f;
3601 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
3603 if (
this == actor.GetRef() && !it->hk_selflock)
3606 node_t* nearest_node =
nullptr;
3607 for (
int i = 0; i < actor->ar_num_nodes; i++)
3610 if (actor->ar_nodes[i].nd_lockgroup == 9999)
3614 if (
this == actor.GetRef() && i == it->hk_hook_node->pos)
3618 if (it->hk_lockgroup != -1 && it->hk_lockgroup != actor->ar_nodes[i].nd_lockgroup)
3622 float n2n_distance = (it->hk_hook_node->AbsPosition - actor->ar_nodes[i].AbsPosition).length();
3623 if (n2n_distance < mindist)
3625 if (distance >= n2n_distance)
3628 distance = n2n_distance;
3629 nearest_node = &actor->ar_nodes[i];
3636 it->hk_lock_node = nearest_node;
3637 it->hk_locked_actor = actor;
3640 if (it->hk_beam->bm_disabled)
3642 it->hk_beam->p2 = it->hk_lock_node;
3643 it->hk_beam->bm_inter_actor = (it->hk_locked_actor !=
nullptr);
3644 it->hk_beam->L = (it->hk_hook_node->AbsPosition - it->hk_lock_node->AbsPosition).length();
3645 it->hk_beam->bm_disabled =
false;
3646 this->AddInterActorBeam(it->hk_beam,
this, it->hk_locked_actor);
3652 else if ((it->hk_locked ==
LOCKED || it->hk_locked ==
PRELOCK) && (mode !=
HOOK_LOCK || !it->hk_beam->bm_inter_actor))
3656 this->RemoveInterActorBeam(it->hk_beam);
3657 if (it->hk_group <= -2)
3659 it->hk_timer = it->hk_timer_preset;
3661 it->hk_lock_node = 0;
3662 it->hk_locked_actor = 0;
3664 it->hk_beam->p2 = &ar_nodes[0];
3665 it->hk_beam->bm_inter_actor =
false;
3666 it->hk_beam->L = (ar_nodes[0].AbsPosition - it->hk_hook_node->AbsPosition).length();
3667 it->hk_beam->bm_disabled =
true;
3674 void Actor::parkingbrakeToggle()
3676 if (ar_state == ActorState::DISPOSED)
3679 ar_parking_brake = !ar_parking_brake;
3681 if (ar_parking_brake)
3689 void Actor::antilockbrakeToggle()
3691 if (ar_state == ActorState::DISPOSED)
3695 alb_mode = !alb_mode;
3698 void Actor::tractioncontrolToggle()
3700 if (ar_state == ActorState::DISPOSED)
3707 void Actor::beaconsToggle()
3709 if (ar_state == ActorState::DISPOSED)
3712 if (m_flares_mode == GfxFlaresMode::NONE)
3723 void Actor::muteAllSounds()
3726 if (ar_state == ActorState::DISPOSED)
3729 for (
int i = 0; i < ar_num_soundsources; i++)
3731 if (ar_soundsources[i].ssi)
3732 ar_soundsources[i].ssi->setEnabled(
false);
3734 #endif // USE_OPENAL
3737 void Actor::unmuteAllSounds()
3740 if (ar_state == ActorState::DISPOSED)
3743 for (
int i = 0; i < ar_num_soundsources; i++)
3745 bool enabled = (ar_soundsources[i].type == -2 || ar_soundsources[i].type == ar_current_cinecam);
3746 ar_soundsources[i].ssi->setEnabled(enabled);
3748 #endif // USE_OPENAL
3751 void Actor::NotifyActorCameraChanged()
3755 if (ar_state == ActorState::DISPOSED)
3758 for (
int i = 0; i < ar_num_soundsources; i++)
3760 bool enabled = (ar_soundsources[i].type == -2 || ar_soundsources[i].type == ar_current_cinecam);
3761 ar_soundsources[i].ssi->setEnabled(enabled);
3763 #endif // USE_OPENAL
3771 int Actor::GetNumActiveConnectedBeams(
int nodeid)
3773 int totallivebeams = 0;
3774 for (
unsigned int ni = 0; ni < ar_node_to_beam_connections[nodeid].size(); ++ni)
3776 if (!ar_beams[ar_node_to_beam_connections[nodeid][ni]].bm_disabled && !ar_beams[ar_node_to_beam_connections[nodeid][ni]].bounded)
3779 return totallivebeams;
3782 bool Actor::isTied()
3784 for (std::vector<tie_t>::iterator it = ar_ties.begin(); it != ar_ties.end(); it++)
3790 bool Actor::isLocked()
3792 for (std::vector<hook_t>::iterator it = ar_hooks.begin(); it != ar_hooks.end(); it++)
3793 if (it->hk_locked ==
LOCKED)
3798 void Actor::updateDashBoards(
float dt)
3809 int gear = ar_engine->GetGear();
3812 int numGears = (int)ar_engine->getNumGears();
3815 String str = String();
3828 int cg = ar_engine->getAutoShift();
3829 if (cg != EngineSim::MANUALMODE)
3831 str = ((cg == EngineSim::REAR) ?
"#ffffff" :
"#868686") + String(
"R\n");
3832 str += ((cg == EngineSim::NEUTRAL) ?
"#ff0012" :
"#8a000a") + String(
"N\n");
3833 str += ((cg == EngineSim::DRIVE) ?
"#12ff00" :
"#248c00") + String(
"D\n");
3834 str += ((cg == EngineSim::TWO) ?
"#ffffff" :
"#868686") + String(
"2\n");
3835 str += ((cg == EngineSim::ONE) ?
"#ffffff" :
"#868686") + String(
"1");
3840 str =
"#b8b8b8M\na\nn\nu";
3845 int autoGear = ar_engine->getAutoShift();
3849 float clutch = ar_engine->GetClutch();
3853 float acc = ar_engine->GetAcceleration();
3857 float rpm = ar_engine->GetEngineRpm();
3861 float turbo = ar_engine->GetTurboPsi() * 3.34f;
3865 bool ign = (ar_engine->hasContact() && !ar_engine->isRunning());
3869 bool batt = (ar_engine->hasContact() && !ar_engine->isRunning());
3873 bool cw = (fabs(ar_engine->GetTorque()) >= ar_engine->GetClutchForce() * 10.0f);
3878 ar_dashboard->setFloat(
DD_BRAKE, ar_brake);
3880 Vector3 cam_dir = this->GetCameraDir();
3881 Vector3 cam_roll = this->GetCameraRoll();
3884 float velocity = ar_nodes[0].Velocity.length();
3885 if (cam_dir != Vector3::ZERO)
3887 velocity = cam_dir.dotProduct(ar_nodes[0].Velocity);
3891 float cur_speed_kph = ar_wheel_speed * 3.6f;
3892 float smooth_kph = (cur_speed_kph * 0.3) + (ar_dashboard->_getFloat(
DD_ENGINE_SPEEDO_KPH) * 0.7);
3896 float cur_speed_mph = ar_wheel_speed * 2.23693629f;
3897 float smooth_mph = (cur_speed_mph * 0.3) + (ar_dashboard->_getFloat(
DD_ENGINE_SPEEDO_MPH) * 0.7);
3901 if (cam_roll != Vector3::ZERO)
3903 float angle = asin(cam_roll.dotProduct(Vector3::UNIT_Y));
3909 float f = Radian(angle).valueDegrees();
3910 ar_dashboard->setFloat(
DD_ROLL, f);
3914 if (this->ar_has_active_shocks)
3917 float roll_corr = - m_stabilizer_shock_ratio * 10.0f;
3920 bool corr_active = (m_stabilizer_shock_request > 0);
3925 if (cam_dir != Vector3::ZERO)
3927 float angle = asin(cam_dir.dotProduct(Vector3::UNIT_Y));
3933 float f = Radian(angle).valueDegrees();
3934 ar_dashboard->setFloat(
DD_PITCH, f);
3941 bool locked = isLocked();
3942 ar_dashboard->setBool(
DD_LOCKED, locked);
3945 bool low_pres = !ar_engine_hydraulics_ready;
3953 int dash_tc_mode = 1;
3956 if (m_tractioncontrol)
3967 int dash_alb_mode = 1;
3970 if (m_antilockbrake)
3982 if (fabs(ar_command_key[0].commandValue) > 0.000001f)
3990 if (ar_num_screwprops)
3995 float throttle = ar_screwprops[i]->getThrottle();
3998 float steering = ar_screwprops[i]->getRudder();
4003 float depth = this->getHeightAboveGround();
4007 Vector3 hdir = this->GetCameraDir();
4008 float knots = hdir.dotProduct(ar_nodes[ar_main_camera_node_pos].Velocity) * 1.9438f;
4013 if (ar_num_aeroengines)
4017 float throttle = ar_aeroengines[i]->getThrottle();
4020 bool failed = ar_aeroengines[i]->isFailed();
4023 float pcent = ar_aeroengines[i]->getRPMpc();
4031 for (
int i = 0; i < ar_num_wings && i <
DD_MAX_WING; i++)
4034 float aoa = ar_wings[i].fa->aoa;
4040 if (ar_num_wings || ar_num_aeroengines)
4044 float ground_speed_kt = ar_nodes[0].Velocity.length() * 1.9438f;
4047 float altitude = ar_nodes[0].AbsPosition.y;
4049 float sea_level_pressure = 101325;
4051 float airpressure = sea_level_pressure * pow(1.0f - 0.0065f * altitude / 288.15f, 5.24947f);
4052 float airdensity = airpressure * 0.0000120896f;
4054 float knots = ground_speed_kt * sqrt(airdensity / 1.225f);
4060 float alt = ar_nodes[0].AbsPosition.y * 1.1811f;
4064 sprintf(altc,
"%03u", (
int)(ar_nodes[0].AbsPosition.y / 30.48f));
4073 if (!m_hud_features_ok)
4075 bool hasEngine = (ar_engine !=
nullptr);
4076 bool hasturbo =
false;
4077 bool autogearVisible =
false;
4081 hasturbo = ar_engine->HasTurbo();
4082 autogearVisible = (ar_engine->getAutoShift() != EngineSim::MANUALMODE);
4098 ar_dashboard->setEnabled(
DD_TIES_MODE, !ar_ties.empty());
4099 ar_dashboard->setEnabled(
DD_LOCKED, !ar_hooks.empty());
4103 ar_dashboard->updateFeatures();
4104 m_hud_features_ok =
true;
4130 ar_dashboard->setBool(
DD_SIGNAL_WARNING, m_blinker_right_lit && m_blinker_left_lit);
4139 Vector3 rollv=curr_truck->ar_nodes[curr_truck->ar_camera_node_pos[0]].RelPosition-curr_truck->ar_nodes[curr_truck->ar_camera_node_roll[0]].RelPosition;
4141 float rollangle=asin(rollv.dotProduct(Vector3::UNIT_Y));
4144 Vector3 dirv=curr_truck->ar_nodes[curr_truck->ar_camera_node_pos[0]].RelPosition-curr_truck->ar_nodes[curr_truck->ar_camera_node_dir[0]].RelPosition;
4146 float pitchangle=asin(dirv.dotProduct(Vector3::UNIT_Y));
4147 Vector3 upv=dirv.crossProduct(-rollv);
4148 if (upv.y<0) rollangle=3.14159-rollangle;
4154 Vector3 idir=curr_truck->ar_nodes[curr_truck->ar_camera_node_pos[0]].RelPosition-curr_truck->ar_nodes[curr_truck->ar_camera_node_dir[0]].RelPosition;
4156 float dirangle=atan2(idir.dotProduct(Vector3::UNIT_X), idir.dotProduct(-Vector3::UNIT_Z));
4158 if (curr_truck->autopilot)
4163 curr_truck->autopilot->getRadioFix(localizers, free_localizer, &vdev, &hdev);
4164 if (hdev>15) hdev=15;
4165 if (hdev<-15) hdev=-15;
4167 if (vdev>15) vdev=15;
4168 if (vdev<-15) vdev=-15;
4173 float vvi=curr_truck->ar_nodes[0].Velocity.y*196.85;
4174 if (vvi<1000.0 && vvi>-1000.0) angle=vvi*0.047;
4175 if (vvi>1000.0 && vvi<6000.0) angle=47.0+(vvi-1000.0)*0.01175;
4176 if (vvi>6000.0) angle=105.75;
4177 if (vvi<-1000.0 && vvi>-6000.0) angle=-47.0+(vvi+1000.0)*0.01175;
4178 if (vvi<-6000.0) angle=-105.75;
4182 if (curr_truck->aeroengines[0]->getType() == AeroEngineType::AE_XPROP)
4189 if (pcent<60.0) angle=-5.0+pcent*1.9167;
4190 else if (pcent<110.0) angle=110.0+(pcent-60.0)*4.075;
4195 if (ftp>1 && curr_truck->aeroengines[1]->getType() == AeroEngineType::AE_XPROP)
4202 if (pcent<60.0) angle=-5.0+pcent*1.9167;
4203 else if (pcent<110.0) angle=110.0+(pcent-60.0)*4.075;
4208 if (ftp>2 && curr_truck->aeroengines[2]->getType() == AeroEngineType::AE_XPROP)
4215 if (pcent<60.0) angle=-5.0+pcent*1.9167;
4216 else if (pcent<110.0) angle=110.0+(pcent-60.0)*4.075;
4221 if (ftp>3 && curr_truck->aeroengines[3]->getType() == AeroEngineType::AE_XPROP)
4228 if (pcent<60.0) angle=-5.0+pcent*1.9167;
4229 else if (pcent<110.0) angle=110.0+(pcent-60.0)*4.075;
4242 ar_dashboard->
update(dt);
4245 void Actor::calculateLocalGForces()
4247 Vector3 cam_dir = this->GetCameraDir();
4248 Vector3 cam_roll = this->GetCameraRoll();
4249 Vector3 cam_up = cam_dir.crossProduct(cam_roll);
4253 float vertacc = m_camera_gforces.dotProduct(cam_up) + gravity;
4254 float longacc = m_camera_gforces.dotProduct(cam_dir);
4255 float latacc = m_camera_gforces.dotProduct(cam_roll);
4257 m_camera_local_gforces_cur = Vector3(vertacc, longacc, latacc) / gravity;
4260 if (m_reset_timer.getMilliseconds() > 500)
4262 m_camera_local_gforces_max.makeCeil(-m_camera_local_gforces_cur);
4263 m_camera_local_gforces_max.makeCeil(+m_camera_local_gforces_cur);
4279 ar_brake = triggerValue;
4303 unsigned int vector_index,
4308 : ar_nb_optimum(7, std::numeric_limits<float>::max())
4309 , ar_nb_reference(7, std::numeric_limits<float>::max())
4310 , m_tyre_pressure(this)
4311 , ar_nb_beams_scale(std::make_pair(1.0f, 1.0f))
4312 , ar_nb_shocks_scale(std::make_pair(1.0f, 1.0f))
4313 , ar_nb_wheels_scale(std::make_pair(1.0f, 1.0f))
4314 , ar_nb_beams_k_interval(std::make_pair(0.1f, 2.0f))
4315 , ar_nb_beams_d_interval(std::make_pair(0.1f, 2.0f))
4316 , ar_nb_shocks_k_interval(std::make_pair(0.1f, 8.0f))
4317 , ar_nb_shocks_d_interval(std::make_pair(0.1f, 8.0f))
4318 , ar_nb_wheels_k_interval(std::make_pair(1.0f, 1.0f))
4319 , ar_nb_wheels_d_interval(std::make_pair(1.0f, 1.0f))
4322 , m_avg_node_position_prev(rq.asr_position)
4324 , m_avg_node_position(rq.asr_position)
4325 , ar_instance_id(actor_id)
4326 , ar_vector_index(vector_index)
4327 , m_avg_proped_wheel_radius(0.2f)
4328 , ar_filename(rq.asr_filename)
4329 , m_section_config(rq.asr_config)
4330 , m_used_actor_entry(rq.asr_cache_entry)
4331 , m_used_skin_entry(rq.asr_skin_entry)
4332 , m_working_tuneup_def(rq.asr_working_tuneup)
4335 , ar_update_physics(false)
4336 , ar_disable_aerodyn_turbulent_drag(false)
4337 , ar_engine_hydraulics_ready(true)
4338 , ar_guisettings_use_engine_max_rpm(false)
4339 , ar_hydro_speed_coupling(false)
4340 , ar_collision_relevant(false)
4341 , ar_is_police(false)
4342 , ar_rescuer_flag(false)
4343 , ar_forward_commands(false)
4344 , ar_import_commands(false)
4345 , ar_toggle_ropes(false)
4346 , ar_toggle_ties(false)
4347 , ar_physics_paused(false)
4350 , m_hud_features_ok(false)
4351 , m_slidenodes_locked(false)
4352 , m_net_initialized(false)
4353 , m_water_contact(false)
4354 , m_water_contact_old(false)
4355 , m_has_command_beams(false)
4356 , m_custom_particles_enabled(false)
4357 , m_beam_break_debug_enabled(false)
4358 , m_beam_deform_debug_enabled(false)
4359 , m_trigger_debug_enabled(false)
4360 , m_disable_default_sounds(false)
4361 , m_disable_smoke(false)
4436 for (
int i = 0; i <
ar_flares.size(); i++)
4438 if (
ar_flares[i].controlnumber == number)
4447 for (
int i = 0; i <
ar_flares.size(); i++)
4487 return Ogre::MaterialPtr();
4492 std::vector<std::string> names;
4495 names.push_back(it->first);
4508 return Ogre::Vector3::ZERO;
4515 std::stringstream buf;
4517 buf <<
"[nodes]" << std::endl;
4527 <<
", loaded:" << (int)(
ar_nodes[i].nd_loaded_mass)
4529 <<
" wheel_rim:" << (int)
ar_nodes[i].nd_rim_node
4531 <<
" (set_node_defaults)"
4545 buf <<
"[beams]" << std::endl;
4549 <<
" " << std::setw(4) << i
4553 <<
" (set_beam_defaults/scale)"
4554 <<
" spring:" << std::setw(8) <<
ar_beams[i].
k
4555 <<
", damp:" << std::setw(8) <<
ar_beams[i].
d
4565 Ogre::DataStreamPtr outStream = Ogre::ResourceGroupManager::getSingleton().createResource(fileName,
RGN_LOGS,
true);
4566 std::string text = buf.str();
4567 outStream->write(text.c_str(), text.length());
4575 if (state.eventlock_present)
4578 if (ev_active && (ev_active != state.event_active_prev))
4580 state.anim_active = !state.anim_active;
4586 state.anim_active = ev_active;
4588 state.event_active_prev = ev_active;