71 #include <fmt/format.h>
72 #include "half/half.hpp"
96 this->DisjoinInterActorBeams();
99 ar_node_to_beam_connections.clear();
100 ar_node_to_node_connections.clear();
103 if (ar_dashboard !=
nullptr)
106 ar_dashboard =
nullptr;
116 for (
int i = 0; i < ar_num_soundsources; i++)
118 if (ar_soundsources[i].ssi)
121 ar_soundsources[i].ssi =
nullptr;
124 ar_num_soundsources = 0;
127 if (ar_autopilot !=
nullptr)
130 ar_autopilot =
nullptr;
133 if (m_fusealge_airfoil)
134 delete m_fusealge_airfoil;
135 m_fusealge_airfoil =
nullptr;
137 if (m_replay_handler)
138 delete m_replay_handler;
139 m_replay_handler =
nullptr;
142 ar_vehicle_ai =
nullptr;
145 if (m_deletion_scene_nodes.size() > 0)
147 for (
unsigned int i = 0; i < m_deletion_scene_nodes.size(); i++)
151 if (!m_deletion_scene_nodes[i])
153 m_deletion_scene_nodes[i]->removeAndDestroyAllChildren();
162 m_deletion_scene_nodes.clear();
165 if (m_deletion_entities.size() > 0)
167 for (
unsigned int i = 0; i < m_deletion_entities.size(); i++)
171 if (!m_deletion_entities[i])
173 m_deletion_entities[i]->detachAllObjectsFromBone();
182 m_deletion_entities.clear();
189 for (
int i = 0; i < ar_num_wings; i++)
195 delete ar_wings[i].fa;
196 if (ar_wings[i].cnode)
198 ar_wings[i].cnode->removeAndDestroyAllChildren();
210 for (
int i = 0; i < ar_num_aeroengines; i++)
212 if (ar_aeroengines[i])
213 delete ar_aeroengines[i];
217 for (
int i = 0; i < ar_num_screwprops; i++)
219 if (ar_screwprops[i])
221 delete ar_screwprops[i];
222 ar_screwprops[i] =
nullptr;
231 ar_airbrakes.clear();
234 for (
int i = 0; i < ar_num_wheels; ++i)
236 delete m_skid_trails[i];
237 m_skid_trails[i] =
nullptr;
241 for (
size_t i = 0; i < this->ar_flares.size(); i++)
245 if (ar_flares[i].snode)
247 ar_flares[i].snode->removeAndDestroyAllChildren();
250 if (ar_flares[i].bbs)
252 if (ar_flares[i].light)
261 this->ar_flares.clear();
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 half_float::half* halfb1 =
reinterpret_cast<half_float::half*
>(netb1 +
sizeof(float) * 3);
516 half_float::half* halfb2 =
reinterpret_cast<half_float::half*
>(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];
540 const int bufpos = (i - 1) * 3;
541 const Vector3 p1rel(halfb1[bufpos + 0], halfb1[bufpos + 1], halfb1[bufpos + 2]);
542 const Vector3 p2rel(halfb2[bufpos + 0], halfb2[bufpos + 1], halfb2[bufpos + 2]);
549 ar_nodes[i].AbsPosition = p1 + tratio * (p2 - p1);
550 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
551 ar_nodes[i].Velocity = (p2 - p1) * 1000.0f / (
float)(oob2->
time - oob1->
time);
554 for (
int i = 0; i < ar_num_wheels; i++)
556 float rp = net_rp1[i] + tratio * (net_rp2[i] - net_rp1[i]);
558 Vector3 axis = ar_wheels[i].wh_axis_node_1->RelPosition - ar_wheels[i].wh_axis_node_0->RelPosition;
560 Plane pplan = Plane(axis, ar_wheels[i].wh_axis_node_0->AbsPosition);
561 Vector3 ortho = -pplan.projectVector(ar_wheels[i].wh_near_attach_node->AbsPosition) - ar_wheels[i].wh_axis_node_0->AbsPosition;
562 Vector3 ray = ortho.crossProduct(axis);
564 ray *= ar_wheels[i].wh_radius;
565 float drp = Math::TWO_PI / (ar_wheels[i].wh_num_nodes / 2);
566 for (
int j = 0; j < ar_wheels[i].wh_num_nodes / 2; j++)
568 Vector3 uray = Quaternion(Radian(rp - drp * j), axis) * ray;
570 ar_wheels[i].wh_nodes[j * 2 + 0]->AbsPosition = ar_wheels[i].wh_axis_node_0->AbsPosition + uray;
571 ar_wheels[i].wh_nodes[j * 2 + 0]->RelPosition = ar_wheels[i].wh_nodes[j * 2]->AbsPosition - ar_origin;
573 ar_wheels[i].wh_nodes[j * 2 + 1]->AbsPosition = ar_wheels[i].wh_axis_node_1->AbsPosition + uray;
574 ar_wheels[i].wh_nodes[j * 2 + 1]->RelPosition = ar_wheels[i].wh_nodes[j * 2 + 1]->AbsPosition - ar_origin;
577 ray *= ar_wheels[i].wh_rim_radius;
578 for (
int j = 0; j < ar_wheels[i].wh_num_rim_nodes / 2; j++)
580 Vector3 uray = Quaternion(Radian(rp - drp * j), axis) * ray;
582 ar_wheels[i].wh_rim_nodes[j * 2 + 0]->AbsPosition = ar_wheels[i].wh_axis_node_0->AbsPosition + uray;
583 ar_wheels[i].wh_rim_nodes[j * 2 + 0]->RelPosition = ar_wheels[i].wh_rim_nodes[j * 2]->AbsPosition - ar_origin;
585 ar_wheels[i].wh_rim_nodes[j * 2 + 1]->AbsPosition = ar_wheels[i].wh_axis_node_1->AbsPosition + uray;
586 ar_wheels[i].wh_rim_nodes[j * 2 + 1]->RelPosition = ar_wheels[i].wh_rim_nodes[j * 2 + 1]->AbsPosition - ar_origin;
589 this->UpdateBoundingBoxes();
590 this->calculateAveragePosition();
599 ar_wheel_speed = netwspeed;
609 if (ar_num_aeroengines > 0)
631 ar_engine->pushNetworkState(engspeed, engforce, engclutch, gear, running, contact, automode);
636 toggleCustomParticles();
642 this->setLightStateMask(oob1->
lightmask);
654 for (
int i = 0; i < index_offset; i++)
656 m_net_updates.pop_front();
659 m_net_initialized =
true;
664 float total_tyre = 0.f;
int num_tyre = 0;
665 float total_loaded = 0.f;
int num_loaded = 0;
666 float total_override = 0.f;
int num_override = 0;
695 LOG(
fmt::format(
"Node masses: total: {} kg, tyre ({} nodes): {} kg, loaded ({} nodes): {} kg, override ({} nodes): {} kg",
697 num_tyre, total_tyre,
698 num_loaded, total_loaded,
699 num_override, total_override));
702 void Actor::recalculateNodeMasses()
709 LOG(
fmt::format(
"recalculateNodeMasses() - before reset (dry mass: {} kg, loaded mass: {} kg, prev. calculated total mass: {} kg",
710 ar_dry_mass, ar_load_mass, ar_total_mass));
715 for (
int i = 0; i < ar_num_nodes; i++)
717 if (!ar_nodes[i].nd_tyre_node)
719 if (!ar_nodes[i].nd_loaded_mass)
722 ar_nodes[i].mass = 0;
724 else if (!ar_nodes[i].nd_override_mass)
727 ar_nodes[i].mass = ar_load_mass / (float)ar_masscount;
732 ar_nodes[i].mass = ar_nodes_override_loadweights[i];
739 for (
int i = 0; i < ar_num_beams; i++)
743 Real half_newlen = ar_beams[i].refL / 2.0;
744 if (!ar_beams[i].p1->nd_tyre_node)
746 if (!ar_beams[i].p2->nd_tyre_node)
751 for (
int i = 0; i < ar_num_beams; i++)
755 Real half_mass = ar_beams[i].refL * ar_dry_mass / len / 2.0f;
756 if (!ar_beams[i].p1->nd_tyre_node)
757 ar_beams[i].p1->mass += half_mass;
758 if (!ar_beams[i].p2->nd_tyre_node)
759 ar_beams[i].p2->mass += half_mass;
765 LOG(
fmt::format(
"recalculateNodeMasses() - average linear density (total beam len: {}m)", len));
770 for (std::vector<rope_t>::iterator it = ar_ropes.begin(); it != ar_ropes.end(); it++)
772 it->rp_beam->p2->mass = 100.0f;
776 for (
int i = 0; i < this->ar_num_cinecams; ++i)
779 ar_nodes[ar_cinecam_node[i]].mass = m_definition->root_module->cinecam[i].node_mass;
784 LOG(
"recalculateNodeMasses() - ropes and cinecams");
789 for (
int i = 0; i < ar_num_nodes; i++)
791 if (!ar_nodes[i].nd_tyre_node &&
792 !(ar_minimass_skip_loaded_nodes && ar_nodes[i].nd_loaded_mass) &&
793 ar_nodes[i].mass < ar_minimass[i])
798 snprintf(buf, 300,
"Node '%d' mass (%f Kg) is too light. Resetting to 'minimass' (%f Kg)", i, ar_nodes[i].mass, ar_minimass[i]);
801 ar_nodes[i].mass = ar_minimass[i];
807 LOG(
fmt::format(
"recalculateNodeMasses() - minimass (ar_minimass_skip_loaded_nodes: {})",
808 ar_minimass_skip_loaded_nodes));
813 for (
int i = 0; i < ar_num_nodes; i++)
817 String msg =
"Node " +
TOSTRING(i) +
" : " +
TOSTRING((
int)ar_nodes[i].mass) +
" kg";
818 if (ar_nodes[i].nd_loaded_mass)
820 if (ar_nodes[i].nd_override_mass)
821 msg +=
" (overriden by node mass)";
823 msg +=
" (normal load node: " +
TOSTRING(ar_load_mass) +
" kg / " +
TOSTRING(ar_masscount) +
" nodes)";
827 ar_total_mass += ar_nodes[i].mass;
829 LOG(
"TOTAL VEHICLE MASS: " +
TOSTRING((
int)ar_total_mass) +
" kg");
832 float Actor::getTotalMass(
bool withLocked)
834 if (ar_state == ActorState::DISPOSED)
838 return ar_total_mass;
840 float mass = ar_total_mass;
842 for (
ActorPtr& actor : ar_linked_actors)
844 mass += actor->ar_total_mass;
850 void Actor::DetermineLinkedActors()
855 ar_linked_actors.clear();
858 std::map<ActorPtr, bool> lookup_table;
860 lookup_table.insert(std::pair<ActorPtr, bool>(
this,
false));
866 for (
auto it_actor = lookup_table.begin(); it_actor != lookup_table.end(); ++it_actor)
868 if (!it_actor->second)
873 auto actor_pair = inter_actor_link.second;
874 if (actor == actor_pair.first || actor == actor_pair.second)
876 auto other_actor = (actor != actor_pair.first) ? actor_pair.first : actor_pair.second;
877 auto ret = lookup_table.insert(std::pair<ActorPtr, bool>(other_actor,
false));
880 ar_linked_actors.push_back(other_actor);
885 it_actor->second =
true;
891 int Actor::getWheelNodeCount()
const
893 return m_wheel_node_count;
896 void Actor::calcNodeConnectivityGraph()
900 ar_node_to_node_connections.resize(ar_num_nodes, std::vector<int>());
901 ar_node_to_beam_connections.resize(ar_num_nodes, std::vector<int>());
903 for (i = 0; i < ar_num_beams; i++)
905 if (ar_beams[i].p1 != NULL && ar_beams[i].p2 != NULL && ar_beams[i].p1->pos >= 0 && ar_beams[i].p2->pos >= 0)
907 ar_node_to_node_connections[ar_beams[i].p1->pos].push_back(ar_beams[i].p2->pos);
908 ar_node_to_beam_connections[ar_beams[i].p1->pos].push_back(i);
909 ar_node_to_node_connections[ar_beams[i].p2->pos].push_back(ar_beams[i].p1->pos);
910 ar_node_to_beam_connections[ar_beams[i].p2->pos].push_back(i);
915 bool Actor::Intersects(
ActorPtr actor, Vector3 offset)
917 Vector3 bb_min = ar_bounding_box.getMinimum() + offset;
918 Vector3 bb_max = ar_bounding_box.getMaximum() + offset;
919 AxisAlignedBox bb = AxisAlignedBox(bb_min, bb_max);
925 for (
int i = 0; i < ar_num_beams; i++)
927 if (!(ar_beams[i].p1->nd_contacter || ar_beams[i].p1->nd_contactable) ||
928 !(ar_beams[i].p2->nd_contacter || ar_beams[i].p2->nd_contactable))
931 Vector3 origin = ar_beams[i].p1->AbsPosition + offset;
932 Vector3 target = ar_beams[i].p2->AbsPosition + offset;
934 Ray ray(origin, target - origin);
943 auto result = Ogre::Math::intersects(ray, a, b, c);
944 if (result.first && result.second < 1.0f)
961 Ray ray(origin, target - origin);
963 for (
int j = 0; j < ar_num_collcabs; j++)
965 int index = ar_collcabs[j] * 3;
966 Vector3 a = ar_nodes[ar_cabs[index + 0]].AbsPosition + offset;
967 Vector3 b = ar_nodes[ar_cabs[index + 1]].AbsPosition + offset;
968 Vector3 c = ar_nodes[ar_cabs[index + 2]].AbsPosition + offset;
970 auto result = Ogre::Math::intersects(ray, a, b, c);
971 if (result.first && result.second < 1.0f)
981 Vector3 Actor::calculateCollisionOffset(Vector3 direction)
983 if (direction == Vector3::ZERO)
984 return Vector3::ZERO;
986 Real max_distance = direction.normalise();
989 Vector3 collision_offset = Vector3::ZERO;
991 while (collision_offset.length() < max_distance)
993 Vector3 bb_min = ar_bounding_box.getMinimum() + collision_offset;
994 Vector3 bb_max = ar_bounding_box.getMaximum() + collision_offset;
995 AxisAlignedBox bb = AxisAlignedBox(bb_min, bb_max);
997 bool collision =
false;
1003 if (!bb.intersects(actor->ar_bounding_box))
1007 if (m_intra_point_col_detector)
1009 for (
int i = 0; i < actor->ar_num_collcabs; i++)
1011 int tmpv = actor->ar_collcabs[i] * 3;
1012 node_t* no = &actor->ar_nodes[actor->ar_cabs[tmpv]];
1013 node_t* na = &actor->ar_nodes[actor->ar_cabs[tmpv + 1]];
1014 node_t* nb = &actor->ar_nodes[actor->ar_cabs[tmpv + 2]];
1016 m_intra_point_col_detector->query(no->
AbsPosition - collision_offset,
1019 actor->ar_collision_range * 3.0f);
1021 if (collision = !m_intra_point_col_detector->hit_list.empty())
1029 float proximity = std::max(.05f, std::sqrt(std::max(m_min_camera_radius, actor->m_min_camera_radius)) / 50.f);
1032 for (
int i = 0; i < ar_num_nodes; i++)
1034 if (!ar_nodes[i].nd_contacter && !ar_nodes[i].nd_contactable)
1037 Vector3 query_position = ar_nodes[i].AbsPosition + collision_offset;
1039 for (
int j = 0; j < actor->ar_num_nodes; j++)
1041 if (!actor->ar_nodes[j].nd_contacter && !actor->ar_nodes[j].nd_contactable)
1044 if (collision = query_position.squaredDistance(actor->ar_nodes[j].AbsPosition) < proximity)
1057 if (!collision && m_inter_point_col_detector)
1059 for (
int i = 0; i < ar_num_collcabs; i++)
1061 int tmpv = ar_collcabs[i] * 3;
1062 node_t* no = &ar_nodes[ar_cabs[tmpv]];
1063 node_t* na = &ar_nodes[ar_cabs[tmpv + 1]];
1064 node_t* nb = &ar_nodes[ar_cabs[tmpv + 2]];
1066 m_inter_point_col_detector->query(no->
AbsPosition + collision_offset,
1069 ar_collision_range * 3.0f);
1071 if (collision = !m_inter_point_col_detector->hit_list.empty())
1083 if (collision = this->Intersects(actor, collision_offset))
1091 collision_offset += direction * 0.05f;
1094 return collision_offset;
1097 void Actor::resolveCollisions(Ogre::Vector3 direction)
1099 if (m_intra_point_col_detector)
1100 m_intra_point_col_detector->UpdateIntraPoint(
true);
1102 if (m_inter_point_col_detector)
1103 m_inter_point_col_detector->UpdateInterPoint(
true);
1105 Vector3 offset = calculateCollisionOffset(direction);
1107 if (offset == Vector3::ZERO)
1111 offset += 0.2f * Vector3(offset.x, 0.0f, offset.z).normalisedCopy();
1113 resetPosition(ar_nodes[0].AbsPosition.x + offset.x, ar_nodes[0].AbsPosition.z + offset.z,
false, this->getMinHeight() + offset.y);
1116 void Actor::resolveCollisions(
float max_distance,
bool consider_up)
1118 if (m_intra_point_col_detector)
1119 m_intra_point_col_detector->UpdateIntraPoint(
true);
1121 if (m_inter_point_col_detector)
1122 m_inter_point_col_detector->UpdateInterPoint(
true);
1124 Vector3 u = Vector3::UNIT_Y;
1125 Vector3 f = Vector3(getDirection().
x, 0.0f, getDirection().
z).normalisedCopy();
1126 Vector3 l = u.crossProduct(f);
1129 Vector3 left = calculateCollisionOffset(+l * max_distance);
1130 Vector3 right = calculateCollisionOffset(-l * left.length());
1131 Vector3 lateral = left.length() < right.length() * 1.1f ? left : right;
1133 Vector3 front = calculateCollisionOffset(+f * lateral.length());
1134 Vector3 back = calculateCollisionOffset(-f * front.length());
1135 Vector3 sagittal = front.length() < back.length() * 1.1f ? front : back;
1137 Vector3 offset = lateral.length() < sagittal.length() * 1.2f ? lateral : sagittal;
1141 Vector3 up = calculateCollisionOffset(+u * offset.length());
1142 if (up.length() * 1.2f < offset.length())
1146 if (offset == Vector3::ZERO)
1150 offset += 0.2f * Vector3(offset.x, 0.0f, offset.z).normalisedCopy();
1152 resetPosition(ar_nodes[0].AbsPosition.x + offset.x, ar_nodes[0].AbsPosition.z + offset.z,
true, this->getMinHeight() + offset.y);
1155 void Actor::calculateAveragePosition()
1160 m_avg_node_position = ar_nodes[ar_custom_camera_node].AbsPosition;
1162 else if (ar_extern_camera_mode == ExtCameraMode::CINECAM && ar_num_cinecams > 0)
1165 m_avg_node_position = ar_nodes[ar_cinecam_node[0]].AbsPosition;
1167 else if (ar_extern_camera_mode == ExtCameraMode::NODE && ar_extern_camera_node !=
NODENUM_INVALID)
1170 m_avg_node_position = ar_nodes[ar_extern_camera_node].AbsPosition;
1175 Vector3 aposition = Vector3::ZERO;
1176 for (
int n = 0; n < ar_num_nodes; n++)
1178 aposition += ar_nodes[n].AbsPosition;
1180 m_avg_node_position = aposition / ar_num_nodes;
1190 void Actor::UpdateBoundingBoxes()
1193 ar_bounding_box = AxisAlignedBox::BOX_NULL;
1194 ar_predicted_bounding_box = AxisAlignedBox::BOX_NULL;
1195 ar_evboxes_bounding_box = AxisAlignedBox::BOX_NULL;
1196 for (
size_t i = 0; i < ar_collision_bounding_boxes.size(); ++i)
1198 ar_collision_bounding_boxes[i] = AxisAlignedBox::BOX_NULL;
1199 ar_predicted_coll_bounding_boxes[i] = AxisAlignedBox::BOX_NULL;
1204 const float CABNODE_MAX_CAMDIST = 15.f;
1205 const Ogre::Vector3 mainCamPos = ar_nodes[ar_main_camera_node_pos].RelPosition;
1208 for (
int i = 0; i < ar_num_nodes; i++)
1210 Vector3 vel = ar_nodes[i].Velocity;
1211 Vector3 pos = ar_nodes[i].AbsPosition;
1212 int16_t cid = ar_nodes[i].nd_coll_bbox_id;
1214 ar_bounding_box.merge(pos);
1215 if (mainCamPos.squaredDistance(ar_nodes[i].RelPosition) < (CABNODE_MAX_CAMDIST*CABNODE_MAX_CAMDIST))
1217 ar_evboxes_bounding_box.merge(pos);
1219 ar_predicted_bounding_box.merge(pos);
1220 ar_predicted_bounding_box.merge(pos + vel);
1221 if (cid != node_t::INVALID_BBOX)
1223 ar_collision_bounding_boxes[cid].merge(pos);
1224 ar_predicted_coll_bounding_boxes[cid].merge(pos);
1225 ar_predicted_coll_bounding_boxes[cid].merge(pos + vel);
1232 for (
size_t i = 0; i < ar_collision_bounding_boxes.size(); ++i)
1239 void Actor::UpdatePhysicsOrigin()
1241 if (ar_nodes[0].RelPosition.squaredLength() > 10000.0)
1243 Vector3 offset = ar_nodes[0].RelPosition;
1244 ar_origin += offset;
1245 for (
int i = 0; i < ar_num_nodes; i++)
1247 ar_nodes[i].RelPosition -= offset;
1252 void Actor::ResetAngle(
float rot)
1255 Vector3 origin = ar_nodes[ar_main_camera_node_pos].AbsPosition;
1259 matrix.FromEulerAnglesXYZ(Radian(0), Radian(-rot + m_spawn_rotation), Radian(0));
1261 for (
int i = 0; i < ar_num_nodes; i++)
1264 ar_nodes[i].AbsPosition -= origin;
1265 ar_nodes[i].AbsPosition = matrix * ar_nodes[i].AbsPosition;
1266 ar_nodes[i].AbsPosition += origin;
1267 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - this->ar_origin;
1270 this->UpdateBoundingBoxes();
1271 calculateAveragePosition();
1274 void Actor::updateInitPosition()
1276 for (
int i = 0; i < ar_num_nodes; i++)
1278 ar_initial_node_positions[i] = ar_nodes[i].AbsPosition;
1282 void Actor::resetPosition(
float px,
float pz,
bool setInitPosition,
float miny)
1285 Vector3 offset = Vector3(px, ar_nodes[0].AbsPosition.y, pz) - ar_nodes[0].AbsPosition;
1286 for (
int i = 0; i < ar_num_nodes; i++)
1288 ar_nodes[i].AbsPosition += offset;
1289 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1293 float vertical_offset = miny - this->getMinHeight();
1296 vertical_offset += std::max(0.0f,
App::GetGameContext()->GetTerrain()->getWater()->GetStaticWaterHeight() - miny);
1298 for (
int i = 1; i < ar_num_nodes; i++)
1300 if (ar_nodes[i].nd_no_ground_contact)
1303 vertical_offset += std::max(0.0f, terrainHeight - (ar_nodes[i].AbsPosition.y + vertical_offset));
1305 for (
int i = 0; i < ar_num_nodes; i++)
1307 ar_nodes[i].AbsPosition.y += vertical_offset;
1308 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1312 float mesh_offset = 0.0f;
1313 for (
int i = 0; i < ar_num_nodes; i++)
1315 if (mesh_offset >= 1.0f)
1317 if (ar_nodes[i].nd_no_ground_contact)
1319 float offset = mesh_offset;
1320 while (offset < 1.0f)
1322 Vector3 query = ar_nodes[i].AbsPosition + Vector3(0.0f, offset, 0.0f);
1323 if (!
App::GetGameContext()->GetTerrain()->GetCollisions()->collisionCorrect(&query,
false))
1325 mesh_offset = offset;
1331 for (
int i = 0; i < ar_num_nodes; i++)
1333 ar_nodes[i].AbsPosition.y += mesh_offset;
1334 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1337 resetPosition(Vector3::ZERO, setInitPosition);
1340 void Actor::resetPosition(Ogre::Vector3 translation,
bool setInitPosition)
1343 if (translation != Vector3::ZERO)
1345 Vector3 offset = translation - ar_nodes[0].AbsPosition;
1346 for (
int i = 0; i < ar_num_nodes; i++)
1348 ar_nodes[i].AbsPosition += offset;
1349 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1353 if (setInitPosition)
1355 for (
int i = 0; i < ar_num_nodes; i++)
1357 ar_initial_node_positions[i] = ar_nodes[i].AbsPosition;
1361 this->UpdateBoundingBoxes();
1362 calculateAveragePosition();
1365 void Actor::softRespawn(Ogre::Vector3 spawnpos, Ogre::Quaternion spawnrot)
1368 this->SyncReset(
false);
1371 ar_origin = spawnpos;
1372 for (
NodeNum_t i = 0; i < ar_num_nodes; i++)
1374 ar_nodes[i].AbsPosition = spawnpos + ar_nodes_spawn_offsets[i];
1375 ar_nodes[i].RelPosition = ar_nodes_spawn_offsets[i];
1376 ar_nodes[i].Forces = Ogre::Vector3::ZERO;
1377 ar_nodes[i].Velocity = Ogre::Vector3::ZERO;
1382 for (
NodeNum_t i = 0; i < ar_num_nodes; i++)
1384 ar_nodes[i].AbsPosition = spawnpos + spawnrot * (ar_nodes[i].AbsPosition - spawnpos);
1385 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1389 void Actor::mouseMove(
NodeNum_t node, Vector3 pos,
float force)
1391 m_mouse_grab_node = node;
1392 m_mouse_grab_move_force = force * std::pow(ar_total_mass / 3000.0f, 0.75f);
1393 m_mouse_grab_pos = pos;
1396 void Actor::toggleWheelDiffMode()
1398 for (
int i = 0; i < m_num_wheel_diffs; ++i)
1400 m_wheel_diffs[i]->ToggleDifferentialMode();
1404 void Actor::toggleAxleDiffMode()
1406 for (
int i = 0; i < m_num_axle_diffs; ++i)
1408 m_axle_diffs[i]->ToggleDifferentialMode();
1412 void Actor::displayAxleDiffMode()
1414 if (m_num_axle_diffs == 0)
1417 _L(
"No inter-axle differential installed on current vehicle!"),
"error.png");
1421 String message =
"";
1422 for (
int i = 0; i < m_num_axle_diffs; ++i)
1424 if (m_axle_diffs[i])
1429 int a1 = m_axle_diffs[i]->di_idx_1 + 1;
1430 int a2 = m_axle_diffs[i]->di_idx_2 + 1;
1432 message += m_axle_diffs[i]->GetDifferentialTypeName();
1436 "Inter-axle differentials:\n" + message,
"cog.png");
1440 void Actor::displayWheelDiffMode()
1442 if (m_num_wheel_diffs == 0)
1445 _L(
"No inter-wheel differential installed on current vehicle!"),
"error.png");
1449 String message =
"";
1450 for (
int i = 0; i < m_num_wheel_diffs; ++i)
1452 if (m_wheel_diffs[i])
1457 message +=
_L(
"Axle ") +
TOSTRING(i + 1) +
": ";
1458 message += m_wheel_diffs[i]->GetDifferentialTypeName();
1462 "Inter-wheel differentials:\n" + message,
"cog.png");
1466 void Actor::displayTransferCaseMode()
1468 if (m_transfer_case)
1471 _L(
"Transfercase switched to: ") + this->getTransferCaseName(),
"cog.png");
1476 _L(
"No transfercase installed on current vehicle!"),
"error.png");
1480 void Actor::toggleTransferCaseMode()
1482 if (!ar_engine || !m_transfer_case || m_transfer_case->tr_ax_2 < 0 || !m_transfer_case->tr_2wd)
1485 if (m_transfer_case->tr_4wd_mode && !m_transfer_case->tr_2wd_lo)
1487 for (
int i = 0; i < m_transfer_case->tr_gear_ratios.size(); i++)
1489 this->toggleTransferCaseGearRatio();
1490 if (m_transfer_case->tr_gear_ratios[0] == 1.0f)
1495 m_transfer_case->tr_4wd_mode = !m_transfer_case->tr_4wd_mode;
1497 if (m_transfer_case->tr_4wd_mode)
1499 ar_wheels[m_wheel_diffs[m_transfer_case->tr_ax_2]->di_idx_1].wh_propulsed = WheelPropulsion::FORWARD;
1500 ar_wheels[m_wheel_diffs[m_transfer_case->tr_ax_2]->di_idx_2].wh_propulsed = WheelPropulsion::FORWARD;
1501 m_num_proped_wheels += 2;
1505 ar_wheels[m_wheel_diffs[m_transfer_case->tr_ax_2]->di_idx_1].wh_propulsed = WheelPropulsion::FORWARD;
1506 ar_wheels[m_wheel_diffs[m_transfer_case->tr_ax_2]->di_idx_2].wh_propulsed = WheelPropulsion::FORWARD;
1507 m_num_proped_wheels -= 2;
1511 void Actor::toggleTransferCaseGearRatio()
1513 if (!ar_engine || !m_transfer_case || m_transfer_case->tr_gear_ratios.size() < 2)
1516 if (m_transfer_case->tr_4wd_mode || m_transfer_case->tr_2wd_lo)
1518 auto gear_ratios = &m_transfer_case->tr_gear_ratios;
1519 std::rotate(gear_ratios->begin(), gear_ratios->begin() + 1, gear_ratios->end());
1521 ar_engine->setTCaseRatio(m_transfer_case->tr_gear_ratios[0]);
1525 String Actor::getTransferCaseName()
1528 if (m_transfer_case)
1530 name += m_transfer_case->tr_4wd_mode ?
"4WD " :
"2WD ";
1531 if (m_transfer_case->tr_gear_ratios[0] > 1.0f)
1532 name +=
"Lo (" +
TOSTRING(m_transfer_case->tr_gear_ratios[0]) +
":1)";
1539 Ogre::Vector3 Actor::getRotationCenter()
1541 Vector3 sum = Vector3::ZERO;
1542 std::vector<Vector3> positions;
1543 for (
int i = 0; i < ar_num_nodes; i++)
1545 Vector3 pos = ar_nodes[i].AbsPosition;
1546 const auto it = std::find_if(positions.begin(), positions.end(),
1547 [pos](
const Vector3 ref) { return pos.positionEquals(ref, 0.01f); });
1548 if (it == positions.end())
1551 positions.push_back(pos);
1554 return sum / positions.size();
1557 float Actor::getMinHeight(
bool skip_virtual_nodes)
1559 float height = std::numeric_limits<float>::max();
1560 for (
int i = 0; i < ar_num_nodes; i++)
1562 if (!skip_virtual_nodes || !ar_nodes[i].nd_no_ground_contact)
1564 height = std::min(ar_nodes[i].AbsPosition.y, height);
1567 return (!skip_virtual_nodes || height < std::numeric_limits<float>::max()) ? height : getMinHeight(
false);
1570 float Actor::getMaxHeight(
bool skip_virtual_nodes)
1572 float height = std::numeric_limits<float>::min();
1573 for (
int i = 0; i < ar_num_nodes; i++)
1575 if (!skip_virtual_nodes || !ar_nodes[i].nd_no_ground_contact)
1577 height = std::max(height, ar_nodes[i].AbsPosition.y);
1580 return (!skip_virtual_nodes || height > std::numeric_limits<float>::min()) ? height : getMaxHeight(
false);
1583 float Actor::getHeightAboveGround(
bool skip_virtual_nodes)
1585 float agl = std::numeric_limits<float>::max();
1586 for (
int i = 0; i < ar_num_nodes; i++)
1588 if (!skip_virtual_nodes || !ar_nodes[i].nd_no_ground_contact)
1590 Vector3 pos = ar_nodes[i].AbsPosition;
1594 return (!skip_virtual_nodes || agl < std::numeric_limits<float>::max()) ? agl : getHeightAboveGround(
false);
1597 float Actor::getHeightAboveGroundBelow(
float height,
bool skip_virtual_nodes)
1599 float agl = std::numeric_limits<float>::max();
1600 for (
int i = 0; i < ar_num_nodes; i++)
1602 if (!skip_virtual_nodes || !ar_nodes[i].nd_no_ground_contact)
1604 Vector3 pos = ar_nodes[i].AbsPosition;
1608 return (!skip_virtual_nodes || agl < std::numeric_limits<float>::max()) ? agl : getHeightAboveGroundBelow(height,
false);
1611 void Actor::reset(
bool keep_position)
1613 if (ar_state == ActorState::DISPOSED)
1618 rq->
amr_type = (keep_position) ? ActorModifyRequest::Type::RESET_ON_SPOT : ActorModifyRequest::Type::RESET_ON_INIT_POS;
1622 void Actor::SoftReset()
1626 float agl = this->getHeightAboveGroundBelow(this->getMaxHeight(
true),
true);
1630 agl = std::min(this->getMinHeight(
true) -
App::GetGameContext()->GetTerrain()->getWater()->GetStaticWaterHeight(), agl);
1635 Vector3 translation = -agl * Vector3::UNIT_Y;
1636 this->resetPosition(ar_nodes[0].AbsPosition + translation,
false);
1637 for (
ActorPtr& actor : ar_linked_actors)
1639 actor->resetPosition(actor->ar_nodes[0].AbsPosition + translation,
false);
1643 m_ongoing_reset =
true;
1646 void Actor::SyncReset(
bool reset_position)
1650 m_reset_timer.reset();
1652 m_camera_local_gforces_cur = Vector3::ZERO;
1653 m_camera_local_gforces_max = Vector3::ZERO;
1655 ar_hydro_dir_state = 0.0;
1656 ar_hydro_aileron_state = 0.0;
1657 ar_hydro_rudder_state = 0.0;
1658 ar_hydro_elevator_state = 0.0;
1659 ar_hydro_dir_wheel_display = 0.0;
1661 ar_fusedrag = Vector3::ZERO;
1663 ar_parking_brake =
false;
1664 ar_trailer_parking_brake =
false;
1665 ar_avg_wheel_speed = 0.0f;
1666 ar_wheel_speed = 0.0f;
1667 ar_wheel_spin = 0.0f;
1670 ar_origin = Vector3::ZERO;
1671 float cur_rot = getRotation();
1672 Vector3 cur_position = ar_nodes[0].AbsPosition;
1674 this->DisjoinInterActorBeams();
1676 for (
int i = 0; i < ar_num_nodes; i++)
1678 ar_nodes[i].AbsPosition = ar_initial_node_positions[i];
1679 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1680 ar_nodes[i].Velocity = Vector3::ZERO;
1681 ar_nodes[i].Forces = Vector3::ZERO;
1684 for (
int i = 0; i < ar_num_beams; i++)
1686 ar_beams[i].maxposstress = ar_beams[i].default_beam_deform;
1687 ar_beams[i].maxnegstress = -ar_beams[i].default_beam_deform;
1688 ar_beams[i].minmaxposnegstress = ar_beams[i].default_beam_deform;
1689 ar_beams[i].strength = ar_beams[i].initial_beam_strength;
1690 ar_beams[i].L = ar_beams[i].refL;
1691 ar_beams[i].stress = 0.0;
1692 ar_beams[i].bm_broken =
false;
1693 ar_beams[i].bm_disabled =
false;
1696 this->applyNodeBeamScales();
1700 for (
auto& h : ar_hooks)
1702 h.hk_beam->bm_disabled =
true;
1705 for (
auto& t : ar_ties)
1707 t.ti_locked_ropable =
nullptr;
1708 t.ti_beam->bm_disabled =
true;
1713 for (
auto& r : ar_ropables)
1715 r.attached_ties = 0;
1716 r.attached_ropes = 0;
1719 for (
int i = 0; i < ar_num_wheels; i++)
1721 ar_wheels[i].wh_speed = 0.0;
1722 ar_wheels[i].wh_torque = 0.0;
1723 ar_wheels[i].wh_avg_speed = 0.0;
1724 ar_wheels[i].wh_is_detached =
false;
1731 ar_engine->startEngine();
1733 ar_engine->setWheelSpin(0.0f);
1736 int num_axle_diffs = (m_transfer_case && m_transfer_case->tr_4wd_mode) ? m_num_axle_diffs + 1 : m_num_axle_diffs;
1737 for (
int i = 0; i < num_axle_diffs; i++)
1738 m_axle_diffs[i]->di_delta_rotation = 0.0f;
1739 for (
int i = 0; i < m_num_wheel_diffs; i++)
1740 m_wheel_diffs[i]->di_delta_rotation = 0.0f;
1741 for (
int i = 0; i < ar_num_aeroengines; i++)
1742 ar_aeroengines[i]->reset();
1743 for (
int i = 0; i < ar_num_screwprops; i++)
1744 ar_screwprops[i]->reset();
1745 for (
int i = 0; i < ar_num_rotators; i++)
1746 ar_rotators[i].angle = 0.0;
1747 for (
int i = 0; i < ar_num_wings; i++)
1748 ar_wings[i].fa->broken =
false;
1750 this->ar_autopilot->reset();
1752 m_buoyance->sink =
false;
1756 hydrobeam.hb_inertia.ResetCmdKeyDelay();
1759 this->GetGfxActor()->ResetFlexbodies();
1762 if (!reset_position)
1764 this->ResetAngle(cur_rot);
1765 this->resetPosition(cur_position,
false);
1766 float agl = this->getHeightAboveGroundBelow(this->getMaxHeight(
true),
true);
1769 agl = std::min(this->getMinHeight(
true) -
App::GetGameContext()->GetTerrain()->getWater()->GetStaticWaterHeight(), agl);
1773 this->resetPosition(ar_nodes[0].AbsPosition - agl * Vector3::UNIT_Y,
false);
1778 this->UpdateBoundingBoxes();
1779 this->calculateAveragePosition();
1784 ar_command_key[i].commandValue = 0.0;
1785 ar_command_key[i].triggerInputValue = 0.0f;
1786 ar_command_key[i].playerInputValue = 0.0f;
1787 for (
auto& b : ar_command_key[i].beams)
1789 b.cmb_state->auto_moving_mode = 0;
1790 b.cmb_state->pressed_center_mode =
false;
1794 this->resetSlideNodes();
1795 if (m_slidenodes_locked)
1797 this->toggleSlideNodeLock();
1800 m_ongoing_reset =
true;
1803 void Actor::applyNodeBeamScales()
1805 for (
int i = 0; i < ar_num_beams; i++)
1807 if ((ar_beams[i].p1->nd_tyre_node || ar_beams[i].p1->nd_rim_node) ||
1808 (ar_beams[i].p2->nd_tyre_node || ar_beams[i].p2->nd_rim_node))
1810 ar_beams[i].k = ar_initial_beam_defaults[i].first * ar_nb_wheels_scale.first;
1811 ar_beams[i].d = ar_initial_beam_defaults[i].second * ar_nb_wheels_scale.second;
1813 else if (ar_beams[i].bounded ==
SHOCK1 || ar_beams[i].bounded ==
SHOCK2 || ar_beams[i].bounded ==
SHOCK3)
1815 ar_beams[i].k = ar_initial_beam_defaults[i].first * ar_nb_shocks_scale.first;;
1816 ar_beams[i].d = ar_initial_beam_defaults[i].second * ar_nb_shocks_scale.second;
1820 ar_beams[i].k = ar_initial_beam_defaults[i].first * ar_nb_beams_scale.first;
1821 ar_beams[i].d = ar_initial_beam_defaults[i].second * ar_nb_beams_scale.second;
1826 void Actor::ForceFeedbackStep(
int steps)
1828 m_force_sensors.out_body_forces = m_force_sensors.accu_body_forces / steps;
1829 if (!ar_hydros.empty())
1831 m_force_sensors.out_hydros_forces = (m_force_sensors.accu_hydros_forces / steps) / ar_hydros.size();
1835 void Actor::HandleAngelScriptEvents(
float dt)
1837 #ifdef USE_ANGELSCRIPT
1839 if (m_water_contact && !m_water_contact_old)
1841 m_water_contact_old = m_water_contact;
1844 #endif // USE_ANGELSCRIPT
1847 void Actor::searchBeamDefaults()
1851 auto old_beams_scale = ar_nb_beams_scale;
1852 auto old_shocks_scale = ar_nb_shocks_scale;
1853 auto old_wheels_scale = ar_nb_wheels_scale;
1855 if (ar_nb_initialized)
1857 ar_nb_beams_scale.first = Math::RangeRandom(ar_nb_beams_k_interval.first, ar_nb_beams_k_interval.second);
1858 ar_nb_beams_scale.second = Math::RangeRandom(ar_nb_beams_d_interval.first, ar_nb_beams_d_interval.second);
1859 ar_nb_shocks_scale.first = Math::RangeRandom(ar_nb_shocks_k_interval.first, ar_nb_shocks_k_interval.second);
1860 ar_nb_shocks_scale.second = Math::RangeRandom(ar_nb_shocks_d_interval.first, ar_nb_shocks_d_interval.second);
1861 ar_nb_wheels_scale.first = Math::RangeRandom(ar_nb_wheels_k_interval.first, ar_nb_wheels_k_interval.second);
1862 ar_nb_wheels_scale.second = Math::RangeRandom(ar_nb_wheels_d_interval.first, ar_nb_wheels_d_interval.second);
1866 ar_nb_beams_scale.first = Math::Clamp(1.0f, ar_nb_beams_k_interval.first, ar_nb_beams_k_interval.second);
1867 ar_nb_beams_scale.second = Math::Clamp(1.0f, ar_nb_beams_d_interval.first, ar_nb_beams_d_interval.second);
1868 ar_nb_shocks_scale.first = Math::Clamp(1.0f, ar_nb_shocks_k_interval.first, ar_nb_shocks_k_interval.second);
1869 ar_nb_shocks_scale.second = Math::Clamp(1.0f, ar_nb_shocks_d_interval.first, ar_nb_shocks_d_interval.second);
1870 ar_nb_wheels_scale.first = Math::Clamp(1.0f, ar_nb_wheels_k_interval.first, ar_nb_wheels_k_interval.second);
1871 ar_nb_wheels_scale.second = Math::Clamp(1.0f, ar_nb_wheels_d_interval.first, ar_nb_wheels_d_interval.second);
1872 ar_nb_reference = std::vector<float>(ar_nb_reference.size(), std::numeric_limits<float>::max());
1873 ar_nb_optimum = std::vector<float>(ar_nb_reference.size(), std::numeric_limits<float>::max());
1876 this->applyNodeBeamScales();
1878 m_ongoing_reset =
false;
1879 this->CalcForcesEulerPrepare(
true);
1880 for (
int i = 0; i < ar_nb_skip_steps; i++)
1882 this->CalcForcesEulerCompute(i == 0, ar_nb_skip_steps);
1883 if (m_ongoing_reset)
1886 m_ongoing_reset =
true;
1888 float sum_movement = 0.0f;
1889 float movement = 0.0f;
1890 float sum_velocity = 0.0f;
1891 float velocity = 0.0f;
1892 float sum_stress = 0.0f;
1893 float stress = 0.0f;
1895 for (
int k = 0; k < ar_nb_measure_steps; k++)
1897 this->CalcForcesEulerCompute(
false, ar_nb_measure_steps);
1898 for (
int i = 0; i < ar_num_nodes; i++)
1900 float v = ar_nodes[i].Velocity.length();
1901 sum_movement += v / (float)ar_nb_measure_steps;
1902 movement = std::max(movement, v);
1904 for (
int i = 0; i < ar_num_beams; i++)
1906 Vector3 dis = (ar_beams[i].p1->RelPosition - ar_beams[i].p2->RelPosition).normalisedCopy();
1907 float v = (ar_beams[i].p1->Velocity - ar_beams[i].p2->Velocity).dotProduct(dis);
1908 sum_velocity += std::abs(v) / (float)ar_nb_measure_steps;
1909 velocity = std::max(velocity, std::abs(v));
1910 sum_stress += std::abs(ar_beams[i].stress) / (float)ar_nb_measure_steps;
1911 stress = std::max(stress, std::abs(ar_beams[i].stress));
1912 if (k == 0 && ar_beams[i].bm_broken)
1917 if (sum_broken > ar_nb_reference[6] ||
1918 stress > ar_nb_reference[0] || velocity > ar_nb_reference[2] || movement > ar_nb_optimum[4] ||
1919 sum_stress > ar_nb_reference[1] || sum_velocity > ar_nb_reference[3] || sum_movement > ar_nb_optimum[5] * 2.f)
1921 ar_nb_beams_scale = old_beams_scale;
1922 ar_nb_shocks_scale = old_shocks_scale;
1923 ar_nb_wheels_scale = old_wheels_scale;
1930 ar_nb_optimum = {stress, sum_stress, velocity, sum_velocity, movement, sum_movement, (float)sum_broken};
1931 if (!ar_nb_initialized)
1933 ar_nb_reference = ar_nb_optimum;
1935 ar_nb_initialized =
true;
1938 void Actor::HandleInputEvents(
float dt)
1940 if (!m_ongoing_reset)
1943 if (m_anglesnap_request > 0)
1945 float rotation = Radian(getRotation()).valueDegrees();
1946 float target_rotation = std::round(rotation / m_anglesnap_request) * m_anglesnap_request;
1947 m_rotation_request = -Degree(target_rotation - rotation).valueRadians();
1948 m_rotation_request_center = getRotationCenter();
1949 m_anglesnap_request = 0;
1952 if (m_rotation_request != 0.0f)
1954 Quaternion rot = Quaternion(Radian(m_rotation_request), Vector3::UNIT_Y);
1956 for (
int i = 0; i < ar_num_nodes; i++)
1958 ar_nodes[i].AbsPosition -= m_rotation_request_center;
1959 ar_nodes[i].AbsPosition = rot * ar_nodes[i].AbsPosition;
1960 ar_nodes[i].AbsPosition += m_rotation_request_center;
1961 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1962 ar_nodes[i].Velocity = rot * ar_nodes[i].Velocity;
1963 ar_nodes[i].Forces = rot * ar_nodes[i].Forces;
1966 m_rotation_request = 0.0f;
1967 this->UpdateBoundingBoxes();
1968 calculateAveragePosition();
1971 if (m_translation_request != Vector3::ZERO)
1973 for (
int i = 0; i < ar_num_nodes; i++)
1975 ar_nodes[i].AbsPosition += m_translation_request;
1976 ar_nodes[i].RelPosition = ar_nodes[i].AbsPosition - ar_origin;
1979 m_translation_request = Vector3::ZERO;
1980 UpdateBoundingBoxes();
1981 calculateAveragePosition();
1985 void Actor::sendStreamSetup()
1996 Ogre::StringUtil::splitFilename(m_used_actor_entry->resource_bundle_path, bname, bpath);
1997 std::string bq_filename =
fmt::format(
"{}:{}", bname, ar_filename);
1998 strncpy(reg.
name, bq_filename.c_str(), 128);
2001 if (m_used_skin_entry !=
nullptr)
2003 strncpy(reg.
skin, m_used_skin_entry->dname.c_str(), 60);
2009 #endif // USE_SOCKETW
2015 void Actor::sendStreamData()
2019 if (ar_net_timer.getMilliseconds() - ar_net_last_update_time < 100)
2022 ar_net_last_update_time = ar_net_timer.getMilliseconds();
2033 unsigned int packet_len = 0;
2050 if (ar_engine->hasContact())
2052 if (ar_engine->isRunning())
2055 switch (ar_engine->getAutoMode())
2069 if (ar_num_aeroengines > 0)
2071 float rpm = ar_aeroengines[0]->getRPM();
2076 send_oob->
brake = ar_brake;
2081 if (getCustomParticleMode())
2084 if (ar_parking_brake)
2086 if (m_tractioncontrol)
2088 if (m_antilockbrake)
2102 float* send_nodes = (
float *)ptr;
2103 packet_len += m_net_total_buffer_size;
2109 Vector3& refpos = ar_nodes[0].AbsPosition;
2110 send_nodes[0] = refpos.x;
2111 send_nodes[1] = refpos.y;
2112 send_nodes[2] = refpos.z;
2114 ptr +=
sizeof(float) * 3;
2117 half_float::half* sbuf = (half_float::half*)ptr;
2118 for (i = 1; i < m_net_first_wheel_node; i++)
2120 Ogre::Vector3 relpos = ar_nodes[i].AbsPosition - ar_nodes[0].AbsPosition;
2121 sbuf[(i-1) * 3 + 0] =
static_cast<half_float::half
>(relpos.x);
2122 sbuf[(i-1) * 3 + 1] =
static_cast<half_float::half
>(relpos.y);
2123 sbuf[(i-1) * 3 + 2] =
static_cast<half_float::half
>(relpos.z);
2125 ptr +=
sizeof(half_float::half) * 3;
2129 float* wfbuf = (
float*)ptr;
2130 for (i = 0; i < ar_num_wheels; i++)
2132 wfbuf[i] = ar_wheels[i].wh_net_rp;
2134 ptr += ar_num_wheels *
sizeof(float);
2137 for (
size_t i = 0; i < m_prop_anim_key_states.size(); i++)
2139 if (m_prop_anim_key_states[i].anim_active)
2142 char& dst_byte = *(ptr + (i / 8));
2143 char mask = ((char)m_prop_anim_key_states[i].anim_active) << (7 - (i % 8));
2153 void Actor::CalcAnimators(
hydrobeam_t const& hydrobeam,
float &cstate,
int &div)
2160 for (spi = 0; spi < ar_num_screwprops; spi++)
2161 if (ar_screwprops[spi])
2162 ctmp += ar_screwprops[spi]->getRudder();
2175 for (spi = 0; spi < ar_num_screwprops; spi++)
2176 if (ar_screwprops[spi])
2177 ctmp += ar_screwprops[spi]->getThrottle();
2188 if (m_num_wheel_diffs && m_wheel_diffs[0])
2190 String name = m_wheel_diffs[0]->GetDifferentialTypeName();
2193 if (name ==
"Split")
2195 if (name ==
"Locked")
2207 float heading = getRotation();
2209 cstate = (heading * 57.29578f) / 360.0f;
2216 float torque = ar_engine->getCrankFactor();
2219 if (torque >= ar_anim_previous_crank)
2220 cstate -= torque / 10.0f;
2224 if (cstate <= -1.0f)
2226 ar_anim_previous_crank = torque;
2234 int shifter = ar_engine->getGear();
2235 if (shifter > m_previous_gear)
2238 ar_anim_shift_timer = 0.2f;
2240 if (shifter < m_previous_gear)
2243 ar_anim_shift_timer = -0.2f;
2245 m_previous_gear = shifter;
2247 if (ar_anim_shift_timer > 0.0f)
2251 if (ar_anim_shift_timer < 0.0f)
2252 ar_anim_shift_timer = 0.0f;
2254 if (ar_anim_shift_timer < 0.0f)
2258 if (ar_anim_shift_timer > 0.0f)
2259 ar_anim_shift_timer = 0.0f;
2268 int shifter = ar_engine->getGear();
2273 else if (shifter < 0)
2279 cstate -= int((shifter - 1.0) / 2.0);
2287 int shifter = ar_engine->getGear();
2295 cstate = shifter % 2;
2303 int shifter = ar_engine->getGear();
2304 int numgears = ar_engine->getNumGears();
2305 cstate -= (shifter + 2.0) / (numgears + 2.0);
2312 float pbrake = ar_parking_brake;
2320 float speedo = ar_wheel_speed / ar_guisettings_speedo_max_kph;
2321 cstate -= speedo * 3.0f;
2328 float tacho = ar_engine->getRPM() / ar_engine->getShiftUpRPM();
2336 float turbo = ar_engine->getTurboPSI() * 3.34;
2337 cstate -= turbo / 67.0f;
2351 float accel = ar_engine->getAcc();
2352 cstate -= accel + 0.06f;
2360 float clutch = ar_engine->getClutch();
2361 cstate -= fabs(1.0f - clutch);
2372 float pcent = ar_aeroengines[aenum]->getRPMpc();
2374 angle = -5.0 + pcent * 1.9167;
2375 else if (pcent < 110.0)
2376 angle = 110.0 + (pcent - 60.0) * 4.075;
2379 cstate -= angle / 314.0f;
2384 float throttle = ar_aeroengines[aenum]->getThrottle();
2390 if (ar_aeroengines[aenum]->getType() == AeroEngineType::AE_XPROP)
2398 if (ar_aeroengines[aenum]->getType() == AeroEngineType::AE_XPROP)
2401 cstate = tp->
pitch / 120.0f;
2407 if (!ar_aeroengines[aenum]->getIgnition())
2411 if (ar_aeroengines[aenum]->isFailed())
2420 float ground_speed_kt = ar_nodes[0].Velocity.length() * 1.9438;
2421 float altitude = ar_nodes[0].AbsPosition.y;
2422 float sea_level_pressure = 101325;
2423 float airpressure = sea_level_pressure * pow(1.0 - 0.0065 * altitude / 288.15, 5.24947);
2424 float airdensity = airpressure * 0.0000120896;
2425 float kt = ground_speed_kt * sqrt(airdensity / 1.225);
2426 cstate -= kt / 100.0f;
2433 float vvi = ar_nodes[0].Velocity.y * 196.85;
2435 cstate -= vvi / 6000.0f;
2438 if (cstate <= -1.0f)
2449 float altimeter = (ar_nodes[0].AbsPosition.y * 1.1811) / 360.0f;
2450 int alti_int = int(altimeter);
2451 float alti_mod = (altimeter - alti_int);
2458 float alti = ar_nodes[0].AbsPosition.y * 1.1811 / 3600.0f;
2459 int alti_int = int(alti);
2460 float alti_mod = (alti - alti_int);
2462 if (cstate <= -1.0f)
2469 float alti = ar_nodes[0].AbsPosition.y * 1.1811 / 36000.0f;
2471 if (cstate <= -1.0f)
2481 if (ar_num_wings > 4)
2482 aoa = (ar_wings[4].fa->aoa) / 25.0f;
2483 if ((ar_nodes[0].Velocity.length() * 1.9438) < 10.0f)
2486 if (cstate <= -1.0f)
2496 Vector3 rollv = this->GetCameraRoll();
2497 Vector3 dirv = this->GetCameraDir();
2498 Vector3 upv = dirv.crossProduct(-rollv);
2499 float rollangle = asin(rollv.dotProduct(Vector3::UNIT_Y));
2501 rollangle = Math::RadiansToDegrees(rollangle);
2504 rollangle = 180.0f - rollangle;
2505 cstate = rollangle / 180.0f;
2509 cstate = cstate - 2.0f;
2516 Vector3 dirv = this->GetCameraDir();
2517 float pitchangle = asin(dirv.dotProduct(Vector3::UNIT_Y));
2519 cstate = (Math::RadiansToDegrees(pitchangle) / 90.0f);
2526 float airbrake = ar_airbrake_intensity;
2528 cstate -= airbrake / 5.0f;
2542 void Actor::CalcCabCollisions()
2544 for (
int i = 0; i < ar_num_nodes; i++)
2546 ar_nodes[i].nd_has_mesh_contact =
false;
2548 if (m_intra_point_col_detector !=
nullptr)
2550 m_intra_point_col_detector->UpdateIntraPoint();
2552 *m_intra_point_col_detector,
2556 ar_intra_collcabrate,
2559 *ar_submesh_ground_model);
2563 void Actor::CalcShocks2(
int i, Real difftoBeamL, Real& k, Real& d, Real v)
2567 k = ar_beams[i].shock->springout;
2568 d = ar_beams[i].shock->dampout;
2570 float logafactor = 1.0f;
2571 if (ar_beams[i].longbound != 0.0f)
2573 logafactor = difftoBeamL / (ar_beams[i].longbound * ar_beams[i].L);
2574 logafactor = std::min(logafactor * logafactor, 1.0f);
2576 k += ar_beams[i].shock->sprogout * k * logafactor;
2577 d += ar_beams[i].shock->dprogout * d * logafactor;
2581 k = ar_beams[i].shock->springin;
2582 d = ar_beams[i].shock->dampin;
2584 float logafactor = 1.0f;
2585 if (ar_beams[i].shortbound != 0.0f)
2587 logafactor = difftoBeamL / (ar_beams[i].shortbound * ar_beams[i].L);
2588 logafactor = std::min(logafactor * logafactor, 1.0f);
2590 k += ar_beams[i].shock->sprogin * k * logafactor;
2591 d += ar_beams[i].shock->dprogin * d * logafactor;
2596 float beamsLep = ar_beams[i].L * 0.8f;
2597 float longboundprelimit = ar_beams[i].longbound * beamsLep;
2598 float shortboundprelimit = -ar_beams[i].shortbound * beamsLep;
2599 if (difftoBeamL > longboundprelimit)
2602 k = ar_beams[i].shock->springout;
2603 d = ar_beams[i].shock->dampout;
2605 float logafactor = 1.0f;
2606 if (ar_beams[i].longbound != 0.0f)
2608 logafactor = difftoBeamL / (ar_beams[i].longbound * ar_beams[i].L);
2609 logafactor = std::min(logafactor * logafactor, 1.0f);
2611 k += ar_beams[i].shock->sprogout * k * logafactor;
2612 d += ar_beams[i].shock->dprogout * d * logafactor;
2615 if (ar_beams[i].longbound != 0.0f)
2617 logafactor = ((difftoBeamL - longboundprelimit) * 5.0f) / (ar_beams[i].longbound * ar_beams[i].L);
2618 logafactor = std::min(logafactor * logafactor, 1.0f);
2620 k += (k + 100.0f) * ar_beams[i].shock->sprogout * logafactor;
2621 d += (d + 100.0f) * ar_beams[i].shock->dprogout * logafactor;
2625 k = ar_beams[i].shock->springin;
2626 d = ar_beams[i].shock->dampin;
2629 else if (difftoBeamL < shortboundprelimit)
2632 k = ar_beams[i].shock->springin;
2633 d = ar_beams[i].shock->dampin;
2635 float logafactor = 1.0f;
2636 if (ar_beams[i].shortbound != 0.0f)
2638 logafactor = difftoBeamL / (ar_beams[i].shortbound * ar_beams[i].L);
2639 logafactor = std::min(logafactor * logafactor, 1.0f);
2641 k += ar_beams[i].shock->sprogin * k * logafactor;
2642 d += ar_beams[i].shock->dprogin * d * logafactor;
2645 if (ar_beams[i].shortbound != 0.0f)
2647 logafactor = ((difftoBeamL - shortboundprelimit) * 5.0f) / (ar_beams[i].shortbound * ar_beams[i].L);
2648 logafactor = std::min(logafactor * logafactor, 1.0f);
2650 k += (k + 100.0f) * ar_beams[i].shock->sprogout * logafactor;
2651 d += (d + 100.0f) * ar_beams[i].shock->dprogout * logafactor;
2655 k = ar_beams[i].shock->springout;
2656 d = ar_beams[i].shock->dampout;
2659 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L || difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
2662 k = std::max(k, ar_beams[i].shock->sbd_spring);
2663 d = std::max(d, ar_beams[i].shock->sbd_damp);
2666 else if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L || difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
2669 k = ar_beams[i].shock->sbd_spring;
2670 d = ar_beams[i].shock->sbd_damp;
2674 void Actor::CalcShocks3(
int i, Real difftoBeamL, Real &k, Real& d, Real v)
2676 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L)
2678 float interp_ratio = difftoBeamL - ar_beams[i].longbound * ar_beams[i].L;
2679 k += (ar_beams[i].shock->sbd_spring - k) * interp_ratio;
2680 d += (ar_beams[i].shock->sbd_damp - d) * interp_ratio;
2682 else if (difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
2684 float interp_ratio = -difftoBeamL - ar_beams[i].shortbound * ar_beams[i].L;
2685 k += (ar_beams[i].shock->sbd_spring - k) * interp_ratio;
2686 d += (ar_beams[i].shock->sbd_damp - d) * interp_ratio;
2690 v = Math::Clamp(std::abs(v), +0.15f, +20.0f);
2691 k = ar_beams[i].shock->springout;
2692 d = ar_beams[i].shock->dampout * ar_beams[i].shock->dslowout * std::min(v, ar_beams[i].shock->splitout) +
2693 ar_beams[i].shock->dampout * ar_beams[i].shock->dfastout * std::max(0.0f, v - ar_beams[i].shock->splitout);
2698 v = Math::Clamp(std::abs(v), +0.15f, +20.0f);
2699 k = ar_beams[i].shock->springin;
2700 d = ar_beams[i].shock->dampin * ar_beams[i].shock->dslowin * std::min(v, ar_beams[i].shock->splitin ) +
2701 ar_beams[i].shock->dampin * ar_beams[i].shock->dfastin * std::max(0.0f, v - ar_beams[i].shock->splitin );
2706 void Actor::CalcTriggers(
int i, Real difftoBeamL,
bool trigger_hooks)
2712 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L || difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
2714 ar_beams[i].shock->trigger_switch_state -= dt;
2715 if (ar_beams[i].shock->trigger_switch_state <= 0.0f)
2716 ar_beams[i].shock->trigger_switch_state = 0.0f;
2719 for (
int scount = i + 1; scount <= i + ar_beams[i].shock->trigger_cmdshort; scount++)
2723 if (m_trigger_debug_enabled && !ar_beams[scount].shock->trigger_enabled && ar_beams[i].shock->last_debug_state != 1)
2725 LOG(
" Trigger disabled. Blocker BeamID " +
TOSTRING(i) +
" enabled trigger " +
TOSTRING(scount));
2726 ar_beams[i].shock->last_debug_state = 1;
2728 ar_beams[scount].shock->trigger_enabled =
false;
2734 for (
int scount = i + 1; scount <= i + ar_beams[i].shock->trigger_cmdlong; scount++)
2738 if (m_trigger_debug_enabled && ar_beams[scount].shock->trigger_enabled && ar_beams[i].shock->last_debug_state != 9)
2740 LOG(
" Trigger enabled. Inverted Blocker BeamID " +
TOSTRING(i) +
" disabled trigger " +
TOSTRING(scount));
2741 ar_beams[i].shock->last_debug_state = 9;
2743 ar_beams[scount].shock->trigger_enabled =
true;
2749 ar_command_key[ar_beams[i].shock->trigger_cmdshort].trigger_cmdkeyblock_state =
false;
2750 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 2)
2752 LOG(
" F-key trigger block released. Blocker BeamID " +
TOSTRING(i) +
" Released F" +
TOSTRING(ar_beams[i].shock->trigger_cmdshort));
2753 ar_beams[i].shock->last_debug_state = 2;
2758 if (!ar_beams[i].shock->trigger_switch_state)
2760 for (
int scount = 0; scount < ar_num_shocks; scount++)
2762 int short1 = ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdshort;
2763 int short2 = ar_beams[i].shock->trigger_cmdshort;
2764 int long1 = ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdlong;
2765 int long2 = ar_beams[i].shock->trigger_cmdlong;
2766 int tmpi = ar_beams[ar_shocks[scount].beamid].shock->beamid;
2767 if (((short1 == short2 && long1 == long2) || (short1 == long2 && long1 == short2)) && i != tmpi)
2769 int tmpcmdkey = ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdlong;
2770 ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdlong = ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdshort;
2771 ar_beams[ar_shocks[scount].beamid].shock->trigger_cmdshort = tmpcmdkey;
2772 ar_beams[i].shock->trigger_switch_state = ar_beams[i].shock->trigger_boundary_t;
2773 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 3)
2775 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));
2776 ar_beams[i].shock->last_debug_state = 3;
2784 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L)
2793 rq->
alr_type = ActorLinkingRequestType::HOOK_UNLOCK;
2806 rq->
alr_type = ActorLinkingRequestType::HOOK_LOCK;
2814 engineTriggerHelper(ar_beams[i].shock->trigger_cmdshort,
EngineTriggerType(ar_beams[i].shock->trigger_cmdlong), 1.0f);
2819 if (!ar_command_key[ar_beams[i].shock->trigger_cmdlong].trigger_cmdkeyblock_state)
2822 ar_command_key[ar_beams[i].shock->trigger_cmdshort].triggerInputValue = 1;
2824 ar_command_key[ar_beams[i].shock->trigger_cmdlong].triggerInputValue = 1;
2825 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 4)
2827 LOG(
" Trigger Longbound activated. Trigger BeamID " +
TOSTRING(i) +
" Triggered F" +
TOSTRING(ar_beams[i].shock->trigger_cmdlong));
2828 ar_beams[i].shock->last_debug_state = 4;
2842 rq->
alr_type = ActorLinkingRequestType::HOOK_UNLOCK;
2855 rq->
alr_type = ActorLinkingRequestType::HOOK_LOCK;
2865 engineTriggerHelper(ar_beams[i].shock->trigger_cmdshort,
EngineTriggerType(ar_beams[i].shock->trigger_cmdlong), triggerValue);
2870 if (!ar_command_key[ar_beams[i].shock->trigger_cmdshort].trigger_cmdkeyblock_state)
2873 ar_command_key[ar_beams[i].shock->trigger_cmdshort].triggerInputValue = 0;
2875 ar_command_key[ar_beams[i].shock->trigger_cmdshort].triggerInputValue = 1;
2877 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 5)
2879 LOG(
" Trigger Shortbound activated. Trigger BeamID " +
TOSTRING(i) +
" Triggered F" +
TOSTRING(ar_beams[i].shock->trigger_cmdshort));
2880 ar_beams[i].shock->last_debug_state = 5;
2891 if (ar_beams[i].longbound - ar_beams[i].shortbound > 0.0f)
2893 float diffPercentage = difftoBeamL / ar_beams[i].L;
2894 float triggerValue = (diffPercentage - ar_beams[i].shortbound) / (ar_beams[i].longbound - ar_beams[i].shortbound);
2896 triggerValue = std::max(0.0f, triggerValue);
2897 triggerValue = std::min(triggerValue, 1.0f);
2901 engineTriggerHelper(ar_beams[i].shock->trigger_cmdshort,
EngineTriggerType(ar_beams[i].shock->trigger_cmdlong), triggerValue);
2906 ar_command_key[ar_beams[i].shock->trigger_cmdshort].triggerInputValue = triggerValue;
2907 ar_command_key[ar_beams[i].shock->trigger_cmdlong].triggerInputValue = triggerValue;
2913 for (
int scount = i + 1; scount <= i + ar_beams[i].shock->trigger_cmdlong; scount++)
2917 if (m_trigger_debug_enabled && ar_beams[scount].shock->trigger_enabled && ar_beams[i].shock->last_debug_state != 6)
2919 LOG(
" Trigger enabled. Blocker BeamID " +
TOSTRING(i) +
" disabled trigger " +
TOSTRING(scount));
2920 ar_beams[i].shock->last_debug_state = 6;
2922 ar_beams[scount].shock->trigger_enabled =
true;
2928 for (
int scount = i + 1; scount <= i + ar_beams[i].shock->trigger_cmdshort; scount++)
2932 if (m_trigger_debug_enabled && !ar_beams[scount].shock->trigger_enabled && ar_beams[i].shock->last_debug_state != 10)
2934 LOG(
" Trigger disabled. Inverted Blocker BeamID " +
TOSTRING(i) +
" enabled trigger " +
TOSTRING(scount));
2935 ar_beams[i].shock->last_debug_state = 10;
2937 ar_beams[scount].shock->trigger_enabled =
false;
2943 ar_beams[i].shock->trigger_switch_state = 0.0f;
2944 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 7)
2946 LOG(
" Trigger switch reset. Switch BeamID " +
TOSTRING(i));
2947 ar_beams[i].shock->last_debug_state = 7;
2950 else if ((ar_beams[i].shock->flags &
SHOCK_FLAG_TRG_CMD_BLOCKER) && !ar_command_key[ar_beams[i].shock->trigger_cmdshort].trigger_cmdkeyblock_state)
2952 ar_command_key[ar_beams[i].shock->trigger_cmdshort].trigger_cmdkeyblock_state =
true;
2953 if (m_trigger_debug_enabled && ar_beams[i].shock->last_debug_state != 8)
2955 LOG(
" F-key trigger blocked. Blocker BeamID " +
TOSTRING(i) +
" Blocked F" +
TOSTRING(ar_beams[i].shock->trigger_cmdshort));
2956 ar_beams[i].shock->last_debug_state = 8;
2963 void Actor::setAirbrakeIntensity(
float intensity)
2965 ar_airbrake_intensity = intensity;
2968 ab->updatePosition((
float)ar_airbrake_intensity / 5.0);
2973 void Actor::updateSkidmarks()
2975 for (
int i = 0; i < ar_num_wheels; i++)
2977 if (!m_skid_trails[i])
2980 for (
int j = 0; j < ar_wheels[i].wh_num_nodes; j++)
2982 auto n = ar_wheels[i].wh_nodes[j];
2983 if (!n || !n->nd_has_ground_contact || n->nd_last_collision_gm ==
nullptr ||
2984 n->nd_last_collision_gm->fx_type != Collisions::FX_HARD)
2988 if (n->nd_avg_collision_slip > 6.f && n->nd_last_collision_slip.squaredLength() > 9.f)
2990 m_skid_trails[i]->update(n->AbsPosition, j, n->nd_avg_collision_slip, n->nd_last_collision_gm->name);
2997 void Actor::prepareInside(
bool inside)
3005 MaterialPtr seatmat = (MaterialPtr)(MaterialManager::getSingleton().getByName(
"driversseat"));
3006 seatmat->setDepthWriteEnabled(
false);
3007 seatmat->setSceneBlending(SBT_TRANSPARENT_ALPHA);
3013 ar_dashboard->setVisible(
false);
3019 MaterialPtr seatmat = (MaterialPtr)(MaterialManager::getSingleton().getByName(
"driversseat"));
3020 seatmat->setDepthWriteEnabled(
true);
3021 seatmat->setSceneBlending(SBT_REPLACE);
3032 m_gfx_actor->SetCastShadows(!inside);
3036 void Actor::toggleHeadlights()
3040 if (ar_state == ActorState::LOCAL_SIMULATED &&
this == player_actor.
GetRef() && ar_forward_commands)
3044 if (actor->ar_state == ActorState::LOCAL_SIMULATED &&
this != actor.GetRef() && actor->ar_import_commands)
3053 m_gfx_actor->SetCabLightsActive(this->getHeadlightsVisible());
3058 void Actor::forceAllFlaresOff()
3060 for (
size_t i = 0; i < ar_flares.size(); i++)
3062 ar_flares[i].snode->setVisible(
false);
3066 void Actor::updateFlareStates(
float dt)
3068 if (m_flares_mode == GfxFlaresMode::NONE) {
return; }
3070 for (
size_t i = 0; i < this->ar_flares.size(); i++)
3073 if (ar_flares[i].blinkdelay != 0)
3075 ar_flares[i].blinkdelay_curr -= dt;
3076 if (ar_flares[i].blinkdelay_curr <= 0)
3078 ar_flares[i].blinkdelay_curr = ar_flares[i].blinkdelay;
3079 ar_flares[i].blinkdelay_state = !ar_flares[i].blinkdelay_state;
3084 ar_flares[i].blinkdelay_state =
true;
3088 bool isvisible =
false;
3089 switch (ar_flares[i].fl_type)
3100 case FlareType::DASHBOARD: isvisible = ar_dashboard->_getBool(ar_flares[i].dashboard_link);
break;
3101 case FlareType::USER: isvisible = this->getCustomLightVisible(ar_flares[i].controlnumber);
break;
3105 isvisible = isvisible && ar_flares[i].blinkdelay_state;
3108 switch (ar_flares[i].fl_type)
3110 case FlareType::BLINKER_LEFT: m_blinker_left_lit = isvisible;
break;
3111 case FlareType::BLINKER_RIGHT: m_blinker_right_lit = isvisible;
break;
3116 if (ar_flares[i].uses_inertia)
3118 ar_flares[i].intensity = ar_flares[i].inertia.CalcSimpleDelay(isvisible, dt);
3122 ar_flares[i].intensity = (float)isvisible;
3129 if (this->getBlinkType() == blink)
3132 setBlinkType(blink);
3137 if (ar_state == ActorState::DISPOSED)
3169 void Actor::autoBlinkReset()
3174 if (this->getBlinkType() ==
BLINK_LEFT && ar_hydro_dir_state < -blink_lock_range)
3177 m_blinker_autoreset =
true;
3180 if (this->getBlinkType() ==
BLINK_LEFT && m_blinker_autoreset && ar_hydro_dir_state > -blink_lock_range)
3184 m_blinker_autoreset =
false;
3188 if (this->getBlinkType() ==
BLINK_RIGHT && ar_hydro_dir_state > blink_lock_range)
3189 m_blinker_autoreset =
true;
3191 if (this->getBlinkType() ==
BLINK_RIGHT && m_blinker_autoreset && ar_hydro_dir_state < blink_lock_range)
3194 m_blinker_autoreset =
false;
3204 this->toggleHeadlights();
3206 this->beaconsToggle();
3215 this->setBlinkType(btype);
3218 m_lightmask = lightmask;
3224 BITMASK_SET_1(lightmask, m_lightmask & m_flaregroups_no_import);
3226 BITMASK_SET_0(lightmask, ~m_lightmask & m_flaregroups_no_import);
3228 this->setLightStateMask(lightmask);
3231 void Actor::toggleCustomParticles()
3233 if (ar_state == ActorState::DISPOSED)
3236 ar_cparticles_active = !ar_cparticles_active;
3242 void Actor::updateSoundSources()
3247 for (
int i = 0; i < ar_num_soundsources; i++)
3250 ar_soundsources[i].ssi->setPosition(ar_nodes[ar_soundsources[i].nodenum].AbsPosition);
3251 ar_soundsources[i].ssi->setVelocity(ar_nodes[ar_soundsources[i].nodenum].Velocity);
3259 void Actor::updateVisual(
float dt)
3261 Vector3 ref(Vector3::UNIT_Y);
3263 updateSoundSources();
3267 if (ar_driveable ==
AIRPLANE && ar_state != ActorState::LOCAL_SLEEPING)
3270 m_avionic_chatter_timer -= dt;
3271 if (m_avionic_chatter_timer < 0)
3274 m_avionic_chatter_timer = Math::RangeRandom(11, 30);
3280 float autoaileron = 0;
3281 float autorudder = 0;
3282 float autoelevator = 0;
3285 ar_autopilot->UpdateIls();
3286 autoaileron = ar_autopilot->getAilerons();
3287 autorudder = ar_autopilot->getRudder();
3288 autoelevator = ar_autopilot->getElevator();
3289 ar_autopilot->gpws_update(ar_posnode_spawn_height);
3291 autoaileron += ar_aileron;
3292 autorudder += ar_rudder;
3293 autoelevator += ar_elevator;
3294 if (autoaileron < -1.0)
3296 if (autoaileron > 1.0)
3298 if (autorudder < -1.0)
3300 if (autorudder > 1.0)
3302 if (autoelevator < -1.0)
3303 autoelevator = -1.0;
3304 if (autoelevator > 1.0)
3306 for (
int i = 0; i < ar_num_wings; i++)
3308 if (ar_wings[i].fa->type ==
'a')
3309 ar_wings[i].fa->setControlDeflection(autoaileron);
3310 if (ar_wings[i].fa->type ==
'b')
3311 ar_wings[i].fa->setControlDeflection(-autoaileron);
3312 if (ar_wings[i].fa->type ==
'r')
3313 ar_wings[i].fa->setControlDeflection(autorudder);
3314 if (ar_wings[i].fa->type ==
'e' || ar_wings[i].fa->type ==
'S' || ar_wings[i].fa->type ==
'T')
3315 ar_wings[i].fa->setControlDeflection(autoelevator);
3316 if (ar_wings[i].fa->type ==
'f')
3317 ar_wings[i].fa->setControlDeflection(
FLAP_ANGLES[ar_aerial_flap]);
3318 if (ar_wings[i].fa->type ==
'c' || ar_wings[i].fa->type ==
'V')
3319 ar_wings[i].fa->setControlDeflection((autoaileron + autoelevator) / 2.0);
3320 if (ar_wings[i].fa->type ==
'd' || ar_wings[i].fa->type ==
'U')
3321 ar_wings[i].fa->setControlDeflection((-autoaileron + autoelevator) / 2.0);
3322 if (ar_wings[i].fa->type ==
'g')
3323 ar_wings[i].fa->setControlDeflection((autoaileron +
FLAP_ANGLES[ar_aerial_flap]) / 2.0);
3324 if (ar_wings[i].fa->type ==
'h')
3325 ar_wings[i].fa->setControlDeflection((-autoaileron +
FLAP_ANGLES[ar_aerial_flap]) / 2.0);
3326 if (ar_wings[i].fa->type ==
'i')
3327 ar_wings[i].fa->setControlDeflection((-autoelevator + autorudder) / 2.0);
3328 if (ar_wings[i].fa->type ==
'j')
3329 ar_wings[i].fa->setControlDeflection((autoelevator + autorudder) / 2.0);
3330 ar_wings[i].fa->updateVerticesPhysics();
3333 ar_hydro_aileron_command = autoaileron;
3334 ar_hydro_rudder_command = autorudder;
3335 ar_hydro_elevator_command = autoelevator;
3343 auto pos = std::find(ar_inter_beams.begin(), ar_inter_beams.end(), beam);
3345 if (pos == ar_inter_beams.end())
3347 ar_inter_beams.push_back(beam);
3352 std::pair<ActorPtr, ActorPtr> actor_pair(
this, other);
3356 if (linked_before != linked_now)
3359 this->DetermineLinkedActors();
3360 for (
ActorPtr& actor : this->ar_linked_actors)
3361 actor->DetermineLinkedActors();
3368 for (
ActorPtr& actor : this->ar_linked_actors)
3386 auto pos = std::find(ar_inter_beams.begin(), ar_inter_beams.end(), beam);
3388 if (pos != ar_inter_beams.end())
3390 ar_inter_beams.erase(pos);
3402 if (linked_before != linked_now)
3405 this->DetermineLinkedActors();
3406 for (
ActorPtr& actor : this->ar_linked_actors)
3407 actor->DetermineLinkedActors();
3411 if (other->
ar_state != ActorState::DISPOSED)
3432 void Actor::DisjoinInterActorBeams()
3440 this->hookToggle(-1, ActorLinkingRequestType::HOOK_RESET);
3441 this->ropeToggle(-1, ActorLinkingRequestType::ROPE_RESET);
3442 this->tieToggle(-1, ActorLinkingRequestType::TIE_RESET);
3447 if (other_actor->ar_state != ActorState::LOCAL_SIMULATED)
3451 other_actor->hookToggle(-1, ActorLinkingRequestType::HOOK_RESET,
NODENUM_INVALID, ar_instance_id);
3452 other_actor->tieToggle(-1, ActorLinkingRequestType::TIE_RESET, ar_instance_id);
3453 other_actor->ropeToggle(-1, ActorLinkingRequestType::ROPE_RESET, ar_instance_id);
3462 bool istied =
false;
3464 for (std::vector<tie_t>::iterator it = ar_ties.begin(); it != ar_ties.end(); it++)
3467 if (group != -1 && (it->ti_group != -1 && it->ti_group != group))
3471 if (mode == ActorLinkingRequestType::TIE_RESET
3472 && forceunlock_filter !=
ACTORINSTANCEID_INVALID && it->ti_locked_actor && it->ti_locked_actor->ar_instance_id != forceunlock_filter)
3480 istied = !it->ti_beam->bm_disabled;
3483 it->ti_tied =
false;
3484 it->ti_tying =
false;
3485 if (it->ti_locked_ropable)
3486 it->ti_locked_ropable->attached_ties--;
3488 it->ti_beam->p2 = &ar_nodes[0];
3489 it->ti_beam->bm_inter_actor =
false;
3490 it->ti_beam->bm_disabled =
true;
3491 if (it->ti_locked_actor !=
this)
3493 this->RemoveInterActorBeam(it->ti_beam, mode);
3495 it->ti_locked_actor =
nullptr;
3500 if (!istied && mode == ActorLinkingRequestType::TIE_TOGGLE)
3502 for (std::vector<tie_t>::iterator it = ar_ties.begin(); it != ar_ties.end(); it++)
3505 if (group != -1 && (it->ti_group != -1 && it->ti_group != group))
3511 float mindist = it->ti_beam->refL;
3512 node_t* nearest_node = 0;
3518 if (actor->ar_state == ActorState::LOCAL_SLEEPING ||
3519 (actor ==
this && it->ti_no_self_lock))
3525 for (std::vector<ropable_t>::iterator itr = actor->ar_ropables.begin(); itr != actor->ar_ropables.end(); itr++)
3528 if (!itr->multilock && itr->attached_ties > 0)
3532 if (
this == actor.GetRef() && itr->node->pos == it->ti_beam->p1->pos)
3536 float dist = (it->ti_beam->p1->AbsPosition - itr->node->AbsPosition).length();
3540 nearest_node = itr->node;
3541 nearest_actor = actor;
3542 locktedto = &(*itr);
3550 it->ti_beam->bm_disabled =
false;
3552 it->ti_locked_actor = nearest_actor;
3553 it->ti_beam->p2 = nearest_node;
3554 it->ti_beam->bm_inter_actor = nearest_actor !=
this;
3555 it->ti_beam->stress = 0;
3556 it->ti_beam->L = it->ti_beam->refL;
3558 it->ti_tying =
true;
3559 it->ti_locked_ropable = locktedto;
3561 if (it->ti_beam->bm_inter_actor)
3563 this->AddInterActorBeam(it->ti_beam, nearest_actor, mode);
3579 for (std::vector<rope_t>::iterator it = ar_ropes.begin(); it != ar_ropes.end(); it++)
3582 if (group != -1 && (it->rp_group != -1 && it->rp_group != group))
3586 if (mode == ActorLinkingRequestType::ROPE_RESET
3587 && forceunlock_filter !=
ACTORINSTANCEID_INVALID && it->rp_locked_actor && it->rp_locked_actor->ar_instance_id != forceunlock_filter)
3597 if (it->rp_locked_ropable)
3598 it->rp_locked_ropable->attached_ropes--;
3599 if (it->rp_locked_actor !=
this)
3601 this->RemoveInterActorBeam(it->rp_beam, mode);
3603 it->rp_locked_actor =
nullptr;
3604 it->rp_locked_ropable =
nullptr;
3606 else if (mode == ActorLinkingRequestType::ROPE_TOGGLE)
3610 float mindist = it->rp_beam->L;
3616 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
3619 for (std::vector<ropable_t>::iterator itr = actor->ar_ropables.begin(); itr != actor->ar_ropables.end(); itr++)
3622 if (!itr->multilock && itr->attached_ropes > 0)
3626 float dist = (it->rp_beam->p1->AbsPosition - itr->node->AbsPosition).length();
3630 nearest_actor = actor;
3640 it->rp_locked_ropable = rop;
3642 if (nearest_actor !=
this)
3644 this->AddInterActorBeam(it->rp_beam, nearest_actor, mode);
3653 ROR_ASSERT(mode == ActorLinkingRequestType::HOOK_LOCK || mode == ActorLinkingRequestType::HOOK_UNLOCK
3654 || mode == ActorLinkingRequestType::HOOK_TOGGLE || mode == ActorLinkingRequestType::HOOK_MOUSE_TOGGLE
3655 || mode == ActorLinkingRequestType::HOOK_RESET);
3658 for (std::vector<hook_t>::iterator it = ar_hooks.begin(); it != ar_hooks.end(); it++)
3660 if (mode == ActorLinkingRequestType::HOOK_MOUSE_TOGGLE && it->hk_hook_node->pos != mousenode)
3665 if (mode == ActorLinkingRequestType::HOOK_TOGGLE && group == -1)
3668 if (it->hk_group <= -2)
3671 if (mode == ActorLinkingRequestType::HOOK_LOCK && group == -2)
3674 if (it->hk_group >= -1 || !it->hk_autolock)
3677 if (mode == ActorLinkingRequestType::HOOK_UNLOCK && group == -2)
3680 if (it->hk_group >= -1 || !it->hk_autolock)
3683 if ((mode == ActorLinkingRequestType::HOOK_LOCK || mode == ActorLinkingRequestType::HOOK_UNLOCK) && group <= -3)
3686 if (it->hk_group != group)
3689 if ((mode == ActorLinkingRequestType::HOOK_LOCK || mode == ActorLinkingRequestType::HOOK_UNLOCK) && group >= -1)
3693 if (mode == ActorLinkingRequestType::HOOK_LOCK && it->hk_timer > 0.0f)
3700 if (mode == ActorLinkingRequestType::HOOK_RESET
3701 && forceunlock_filter !=
ACTORINSTANCEID_INVALID && it->hk_locked_actor && it->hk_locked_actor->ar_instance_id != forceunlock_filter)
3706 ActorPtr prev_locked_actor = it->hk_locked_actor;
3709 if ((mode != ActorLinkingRequestType::HOOK_UNLOCK && mode != ActorLinkingRequestType::HOOK_RESET) && it->hk_locked ==
UNLOCKED)
3713 float mindist = it->hk_lockrange;
3714 float distance = 100000000.0f;
3718 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
3720 if (
this == actor.GetRef() && !it->hk_selflock)
3723 node_t* nearest_node =
nullptr;
3724 for (
int i = 0; i < actor->ar_num_nodes; i++)
3727 if (actor->ar_nodes[i].nd_lockgroup == 9999)
3731 if (
this == actor.GetRef() && i == it->hk_hook_node->pos)
3735 if (it->hk_lockgroup != -1 && it->hk_lockgroup != actor->ar_nodes[i].nd_lockgroup)
3739 float n2n_distance = (it->hk_hook_node->AbsPosition - actor->ar_nodes[i].AbsPosition).length();
3740 if (n2n_distance < mindist)
3742 if (distance >= n2n_distance)
3745 distance = n2n_distance;
3746 nearest_node = &actor->ar_nodes[i];
3753 it->hk_lock_node = nearest_node;
3754 it->hk_locked_actor = actor;
3757 if (it->hk_beam->bm_disabled)
3759 it->hk_beam->p2 = it->hk_lock_node;
3760 it->hk_beam->bm_inter_actor = (it->hk_locked_actor !=
nullptr);
3761 it->hk_beam->L = (it->hk_hook_node->AbsPosition - it->hk_lock_node->AbsPosition).length();
3762 it->hk_beam->bm_disabled =
false;
3763 this->AddInterActorBeam(it->hk_beam, it->hk_locked_actor, mode);
3769 else if ((it->hk_locked ==
LOCKED || it->hk_locked ==
PRELOCK) && (mode != ActorLinkingRequestType::HOOK_LOCK || !it->hk_beam->bm_inter_actor))
3773 this->RemoveInterActorBeam(it->hk_beam, mode);
3774 if (it->hk_group <= -2)
3777 it->hk_timer = (mode == ActorLinkingRequestType::HOOK_RESET) ? 0.f : it->hk_timer_preset;
3779 it->hk_lock_node = 0;
3780 it->hk_locked_actor = 0;
3782 it->hk_beam->p2 = &ar_nodes[0];
3783 it->hk_beam->bm_inter_actor =
false;
3784 it->hk_beam->L = (ar_nodes[0].AbsPosition - it->hk_hook_node->AbsPosition).length();
3785 it->hk_beam->bm_disabled =
true;
3790 void Actor::parkingbrakeToggle()
3792 if (ar_state == ActorState::DISPOSED)
3795 ar_parking_brake = !ar_parking_brake;
3797 if (ar_parking_brake)
3805 void Actor::antilockbrakeToggle()
3807 if (ar_state == ActorState::DISPOSED)
3811 alb_mode = !alb_mode;
3814 void Actor::tractioncontrolToggle()
3816 if (ar_state == ActorState::DISPOSED)
3823 void Actor::beaconsToggle()
3825 if (ar_state == ActorState::DISPOSED)
3828 if (m_flares_mode == GfxFlaresMode::NONE)
3839 void Actor::muteAllSounds()
3842 if (ar_state == ActorState::DISPOSED)
3845 for (
int i = 0; i < ar_num_soundsources; i++)
3847 if (ar_soundsources[i].ssi)
3848 ar_soundsources[i].ssi->setEnabled(
false);
3850 #endif // USE_OPENAL
3853 void Actor::unmuteAllSounds()
3856 if (ar_state == ActorState::DISPOSED)
3859 for (
int i = 0; i < ar_num_soundsources; i++)
3861 bool enabled = (ar_soundsources[i].type == -2 || ar_soundsources[i].type == ar_current_cinecam);
3862 ar_soundsources[i].ssi->setEnabled(enabled);
3864 #endif // USE_OPENAL
3867 void Actor::NotifyActorCameraChanged()
3871 if (ar_state == ActorState::DISPOSED)
3874 for (
int i = 0; i < ar_num_soundsources; i++)
3876 bool enabled = (ar_soundsources[i].type == -2 || ar_soundsources[i].type == ar_current_cinecam);
3877 ar_soundsources[i].ssi->setEnabled(enabled);
3879 #endif // USE_OPENAL
3887 int Actor::GetNumActiveConnectedBeams(
int nodeid)
3889 int totallivebeams = 0;
3890 for (
unsigned int ni = 0; ni < ar_node_to_beam_connections[nodeid].size(); ++ni)
3892 if (!ar_beams[ar_node_to_beam_connections[nodeid][ni]].bm_disabled && !ar_beams[ar_node_to_beam_connections[nodeid][ni]].bounded)
3895 return totallivebeams;
3898 bool Actor::isTied()
3900 for (std::vector<tie_t>::iterator it = ar_ties.begin(); it != ar_ties.end(); it++)
3906 bool Actor::isLocked()
3908 for (std::vector<hook_t>::iterator it = ar_hooks.begin(); it != ar_hooks.end(); it++)
3909 if (it->hk_locked ==
LOCKED)
3914 void Actor::updateDashBoards(
float dt)
3925 int gear = ar_engine->getGear();
3928 int numGears = (int)ar_engine->getNumGears();
3931 String str = String();
3944 int cg = ar_engine->getAutoShift();
3947 str = ((cg ==
Engine::REAR) ?
"#ffffff" :
"#868686") + String(
"R\n");
3948 str += ((cg ==
Engine::NEUTRAL) ?
"#ff0012" :
"#8a000a") + String(
"N\n");
3949 str += ((cg ==
Engine::DRIVE) ?
"#12ff00" :
"#248c00") + String(
"D\n");
3950 str += ((cg ==
Engine::TWO) ?
"#ffffff" :
"#868686") + String(
"2\n");
3951 str += ((cg ==
Engine::ONE) ?
"#ffffff" :
"#868686") + String(
"1");
3956 str =
"#b8b8b8M\na\nn\nu";
3961 int autoGear = ar_engine->getAutoShift();
3965 float clutch = ar_engine->getClutch();
3969 float acc = ar_engine->getAcc();
3973 float rpm = ar_engine->getRPM();
3977 float turbo = ar_engine->getTurboPSI() * 3.34f;
3981 bool ign = (ar_engine->hasContact() && !ar_engine->isRunning());
3985 bool batt = (ar_engine->hasContact() && !ar_engine->isRunning());
3989 bool cw = (fabs(ar_engine->getTorque()) >= ar_engine->getClutchForce() * 10.0f);
3994 ar_dashboard->setFloat(
DD_BRAKE, ar_brake);
3996 Vector3 cam_dir = this->GetCameraDir();
3997 Vector3 cam_roll = this->GetCameraRoll();
4000 float velocity = ar_nodes[0].Velocity.length();
4001 if (cam_dir != Vector3::ZERO)
4003 velocity = cam_dir.dotProduct(ar_nodes[0].Velocity);
4007 float cur_speed_kph = ar_wheel_speed * 3.6f;
4008 float smooth_kph = (cur_speed_kph * 0.3) + (ar_dashboard->_getFloat(
DD_ENGINE_SPEEDO_KPH) * 0.7);
4012 float cur_speed_mph = ar_wheel_speed * 2.23693629f;
4013 float smooth_mph = (cur_speed_mph * 0.3) + (ar_dashboard->_getFloat(
DD_ENGINE_SPEEDO_MPH) * 0.7);
4017 if (cam_roll != Vector3::ZERO)
4019 float angle = asin(cam_roll.dotProduct(Vector3::UNIT_Y));
4025 float f = Radian(angle).valueDegrees();
4026 ar_dashboard->setFloat(
DD_ROLL, f);
4030 if (this->ar_has_active_shocks)
4033 float roll_corr = - m_stabilizer_shock_ratio * 10.0f;
4036 bool corr_active = (m_stabilizer_shock_request > 0);
4041 if (cam_dir != Vector3::ZERO)
4043 float angle = asin(cam_dir.dotProduct(Vector3::UNIT_Y));
4049 float f = Radian(angle).valueDegrees();
4050 ar_dashboard->setFloat(
DD_PITCH, f);
4057 bool locked = isLocked();
4058 ar_dashboard->setBool(
DD_LOCKED, locked);
4061 bool low_pres = !ar_engine_hydraulics_ready;
4069 int dash_tc_mode = 1;
4072 if (m_tractioncontrol)
4083 int dash_alb_mode = 1;
4086 if (m_antilockbrake)
4098 if (fabs(ar_command_key[0].commandValue) > 0.000001f)
4106 if (ar_num_screwprops)
4111 float throttle = ar_screwprops[i]->getThrottle();
4114 float steering = ar_screwprops[i]->getRudder();
4119 float depth = this->getHeightAboveGround();
4123 Vector3 hdir = this->GetCameraDir();
4124 float knots = hdir.dotProduct(ar_nodes[ar_main_camera_node_pos].Velocity) * 1.9438f;
4129 if (ar_num_aeroengines)
4133 float throttle = ar_aeroengines[i]->getThrottle();
4136 bool failed = ar_aeroengines[i]->isFailed();
4139 float pcent = ar_aeroengines[i]->getRPMpc();
4147 for (
int i = 0; i < ar_num_wings && i <
DD_MAX_WING; i++)
4150 float aoa = ar_wings[i].fa->aoa;
4156 if (ar_num_wings || ar_num_aeroengines)
4160 float ground_speed_kt = ar_nodes[0].Velocity.length() * 1.9438f;
4163 float altitude = ar_nodes[0].AbsPosition.y;
4165 float sea_level_pressure = 101325;
4167 float airpressure = sea_level_pressure * pow(1.0f - 0.0065f * altitude / 288.15f, 5.24947f);
4168 float airdensity = airpressure * 0.0000120896f;
4170 float knots = ground_speed_kt * sqrt(airdensity / 1.225f);
4176 float alt = ar_nodes[0].AbsPosition.y * 1.1811f;
4180 sprintf(altc,
"%03u", (
int)(ar_nodes[0].AbsPosition.y / 30.48f));
4189 if (!m_hud_features_ok)
4191 bool hasEngine = (ar_engine !=
nullptr);
4192 bool hasturbo =
false;
4193 bool autogearVisible =
false;
4197 hasturbo = ar_engine->hasTurbo();
4214 ar_dashboard->setEnabled(
DD_TIES_MODE, !ar_ties.empty());
4215 ar_dashboard->setEnabled(
DD_LOCKED, !ar_hooks.empty());
4219 ar_dashboard->updateFeatures();
4220 m_hud_features_ok =
true;
4246 ar_dashboard->setBool(
DD_SIGNAL_WARNING, m_blinker_right_lit && m_blinker_left_lit);
4255 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;
4257 float rollangle=asin(rollv.dotProduct(Vector3::UNIT_Y));
4260 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;
4262 float pitchangle=asin(dirv.dotProduct(Vector3::UNIT_Y));
4263 Vector3 upv=dirv.crossProduct(-rollv);
4264 if (upv.y<0) rollangle=3.14159-rollangle;
4270 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;
4272 float dirangle=atan2(idir.dotProduct(Vector3::UNIT_X), idir.dotProduct(-Vector3::UNIT_Z));
4274 if (curr_truck->autopilot)
4279 curr_truck->autopilot->getRadioFix(localizers, free_localizer, &vdev, &hdev);
4280 if (hdev>15) hdev=15;
4281 if (hdev<-15) hdev=-15;
4283 if (vdev>15) vdev=15;
4284 if (vdev<-15) vdev=-15;
4289 float vvi=curr_truck->ar_nodes[0].Velocity.y*196.85;
4290 if (vvi<1000.0 && vvi>-1000.0) angle=vvi*0.047;
4291 if (vvi>1000.0 && vvi<6000.0) angle=47.0+(vvi-1000.0)*0.01175;
4292 if (vvi>6000.0) angle=105.75;
4293 if (vvi<-1000.0 && vvi>-6000.0) angle=-47.0+(vvi+1000.0)*0.01175;
4294 if (vvi<-6000.0) angle=-105.75;
4298 if (curr_truck->aeroengines[0]->getType() == AeroEngineType::AE_XPROP)
4305 if (pcent<60.0) angle=-5.0+pcent*1.9167;
4306 else if (pcent<110.0) angle=110.0+(pcent-60.0)*4.075;
4311 if (ftp>1 && curr_truck->aeroengines[1]->getType() == AeroEngineType::AE_XPROP)
4318 if (pcent<60.0) angle=-5.0+pcent*1.9167;
4319 else if (pcent<110.0) angle=110.0+(pcent-60.0)*4.075;
4324 if (ftp>2 && curr_truck->aeroengines[2]->getType() == AeroEngineType::AE_XPROP)
4331 if (pcent<60.0) angle=-5.0+pcent*1.9167;
4332 else if (pcent<110.0) angle=110.0+(pcent-60.0)*4.075;
4337 if (ftp>3 && curr_truck->aeroengines[3]->getType() == AeroEngineType::AE_XPROP)
4344 if (pcent<60.0) angle=-5.0+pcent*1.9167;
4345 else if (pcent<110.0) angle=110.0+(pcent-60.0)*4.075;
4358 ar_dashboard->
update(dt);
4361 void Actor::calculateLocalGForces()
4363 Vector3 cam_dir = this->GetCameraDir();
4364 Vector3 cam_roll = this->GetCameraRoll();
4365 Vector3 cam_up = cam_dir.crossProduct(cam_roll);
4369 float vertacc = m_camera_gforces.dotProduct(cam_up) + gravity;
4370 float longacc = m_camera_gforces.dotProduct(cam_dir);
4371 float latacc = m_camera_gforces.dotProduct(cam_roll);
4373 m_camera_local_gforces_cur = Vector3(vertacc, longacc, latacc) / gravity;
4376 if (m_reset_timer.getMilliseconds() > 500)
4378 m_camera_local_gforces_max.makeCeil(-m_camera_local_gforces_cur);
4379 m_camera_local_gforces_max.makeCeil(+m_camera_local_gforces_cur);
4391 ar_engine->setClutch(triggerValue);
4394 ar_brake = triggerValue;
4398 ar_engine->setAcc(triggerValue);
4405 ar_engine->shift(1);
4409 ar_engine->shift(-1);
4418 unsigned int vector_index,
4423 : ar_nb_optimum(7, std::numeric_limits<float>::max())
4424 , ar_nb_reference(7, std::numeric_limits<float>::max())
4425 , m_tyre_pressure(this)
4426 , ar_nb_beams_scale(std::make_pair(1.0f, 1.0f))
4427 , ar_nb_shocks_scale(std::make_pair(1.0f, 1.0f))
4428 , ar_nb_wheels_scale(std::make_pair(1.0f, 1.0f))
4429 , ar_nb_beams_k_interval(std::make_pair(0.1f, 2.0f))
4430 , ar_nb_beams_d_interval(std::make_pair(0.1f, 2.0f))
4431 , ar_nb_shocks_k_interval(std::make_pair(0.1f, 8.0f))
4432 , ar_nb_shocks_d_interval(std::make_pair(0.1f, 8.0f))
4433 , ar_nb_wheels_k_interval(std::make_pair(1.0f, 1.0f))
4434 , ar_nb_wheels_d_interval(std::make_pair(1.0f, 1.0f))
4437 , m_avg_node_position_prev(rq.asr_position)
4439 , m_avg_node_position(rq.asr_position)
4440 , ar_instance_id(actor_id)
4441 , ar_vector_index(vector_index)
4442 , m_avg_proped_wheel_radius(0.2f)
4443 , ar_filename(rq.asr_cache_entry->fname)
4444 , m_section_config(rq.asr_config)
4445 , m_used_actor_entry(rq.asr_cache_entry)
4446 , m_used_skin_entry(rq.asr_skin_entry)
4447 , m_working_tuneup_def(rq.asr_working_tuneup)
4450 , ar_update_physics(false)
4451 , ar_disable_aerodyn_turbulent_drag(false)
4452 , ar_engine_hydraulics_ready(true)
4453 , ar_guisettings_use_engine_max_rpm(false)
4454 , ar_hydro_speed_coupling(false)
4455 , ar_collision_relevant(false)
4456 , ar_is_police(false)
4457 , ar_rescuer_flag(false)
4458 , ar_forward_commands(false)
4459 , ar_import_commands(false)
4460 , ar_toggle_ropes(false)
4461 , ar_toggle_ties(false)
4464 , m_hud_features_ok(false)
4465 , m_slidenodes_locked(false)
4466 , m_net_initialized(false)
4467 , m_water_contact(false)
4468 , m_water_contact_old(false)
4469 , m_has_command_beams(false)
4470 , ar_cparticles_active(false)
4471 , m_beam_break_debug_enabled(false)
4472 , m_beam_deform_debug_enabled(false)
4473 , m_trigger_debug_enabled(false)
4474 , m_disable_default_sounds(false)
4475 , m_disable_smoke(false)
4555 for (
int i = 0; i <
ar_flares.size(); i++)
4557 if (
ar_flares[i].controlnumber == number)
4566 for (
int i = 0; i <
ar_flares.size(); i++)
4606 return Ogre::MaterialPtr();
4611 std::vector<std::string> names;
4614 names.push_back(it->first);
4627 return Ogre::Vector3::ZERO;
4658 std::stringstream buf;
4660 buf <<
"[nodes]" << std::endl;
4670 <<
", loaded:" << (int)(
ar_nodes[i].nd_loaded_mass)
4672 <<
" wheel_rim:" << (int)
ar_nodes[i].nd_rim_node
4674 <<
" (set_node_defaults)"
4688 buf <<
"[beams]" << std::endl;
4692 <<
" " << std::setw(4) << i
4696 <<
" (set_beam_defaults/scale)"
4697 <<
" spring:" << std::setw(8) <<
ar_beams[i].
k
4698 <<
", damp:" << std::setw(8) <<
ar_beams[i].
d
4708 Ogre::DataStreamPtr outStream = Ogre::ResourceGroupManager::getSingleton().createResource(fileName,
RGN_LOGS,
true);
4709 std::string text = buf.str();
4710 outStream->write(text.c_str(), text.length());
4718 if (state.eventlock_present)
4721 if (ev_active && (ev_active != state.event_active_prev))
4723 state.anim_active = !state.anim_active;
4729 state.anim_active = ev_active;
4731 state.event_active_prev = ev_active;
4819 "Cannot change simulation attributes in multiplayer mode.");
4921 default:
return 0.f;