/* =========================================================================== Copyright (C) 2018-2024 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "vehicle.h" #include "player.h" #include "g_phys.h" CLASS_DECLARATION(DrivableVehicle, VehicleHalfTrack, "VehicleHalfTrack") { {&EV_Damage, &VehicleHalfTrack::EventDamage}, {&EV_Killed, &VehicleHalfTrack::Killed }, {NULL, NULL } }; VehicleHalfTrack::VehicleHalfTrack() { } void VehicleHalfTrack::Think() { vmove_t vm; flags |= FL_POSTTHINK; prev_velocity = velocity; SetSlotsNonSolid(); SetMoveInfo(&vm); VmoveSingle(&vm); GetMoveInfo(&vm); SetSlotsSolid(); } void VehicleHalfTrack::Postthink() { float turn; Vector i, j, k; int index; trace_t trace; Vector normalsum; int numnormals; Vector temp; Vector pitch, roll; Vector acceleration; Vector atmp, atmp2, aup; VehicleBase *v; VehicleBase *last; float drivespeed; Vector primal_angles; Vector vTmp; Vector n_angles; primal_angles = angles; if (drivable) { if (m_bAutoPilot) { AutoPilot(); } currentspeed = moveimpulse; turnangle = turnangle * 0.25 + turnimpulse; turnangle = Q_clamp_float(turnangle, -maxturnrate, maxturnrate); real_velocity = origin - prev_origin; prev_origin = origin; prev_acceleration = real_acceleration; real_acceleration = real_velocity - prev_velocity; prev_velocity = real_velocity; acceleration = real_acceleration - prev_acceleration; temp = angles; temp.AngleVectorsLeft(&i, &j, &k); j = vec_zero - j; numnormals = 0; for (index = 0; index < MAX_CORNERS; index++) { Vector start, end; Vector boxoffset; Vector t_mins(-8, -8, -8), t_maxs(8, 8, 8); boxoffset = Corners[index]; start = origin + i * boxoffset[0] + j * boxoffset[1] + k * boxoffset[2]; end = start + Vector(0, 0, -400); trace = G_Trace(start, t_mins, t_maxs, end, this, MASK_VEHICLE_TIRES, false, "Vehicle::PostThink Corners"); if (trace.fraction != 1.0 || trace.startsolid) { normalsum += trace.plane.normal; } } angles[2] = 0; if (m_iNumNormals > 1) { temp = normalsum / numnormals; temp.normalize(); i = temp.CrossProduct(temp, j); pitch = i; angles[0] = -pitch.toPitch(); } turn = turnangle / 200.0; if (groundentity) { Vector newvel; Vector flatvel; velocity[0] *= 0.925f; velocity[1] *= 0.925f; flatvel = orientation[0]; velocity += flatvel * currentspeed; flatvel[2] = 0; drivespeed = Q_clamp_float(velocity * flatvel, -speed, speed); newvel = flatvel * drivespeed; velocity[0] = newvel[0]; velocity[1] = newvel[1]; velocity[2] += drivespeed * jumpimpulse; avelocity *= 0.05f; if (steerinplace) { if (drivespeed < 350) { drivespeed = 350; } } avelocity.y += turn * drivespeed; } else { avelocity *= 0.1f; } angles += avelocity * level.frametime; setAngles(angles); } drivespeed = acceleration * orientation[0]; if (drivable && driver.ent) { str sound_name; if (currentspeed > 0) { sound_name = "snd_forward"; } else if (currentspeed < 0) { sound_name = "snd_backward"; } else { sound_name = "snd_idle"; } LoopSound(sound_name); } i = orientation[0]; j = orientation[1]; k = orientation[2]; if (driver.ent) { driver.ent->setOrigin(origin + i * driveroffset[0] + j * driveroffset[1] + k * driveroffset[2]); if (drivable) { // clear the driver velocity driver.ent->velocity = vec_zero; // set the driver angles to the vehicle's angle driver.ent->setAngles(angles); } } n_angles = (angles - primal_angles) * level.frametime; if (n_angles.x > 180 || n_angles.x < -180) { n_angles.x = 0; } if (n_angles.y > 180 || n_angles.y < -180) { n_angles.y = 0; } if (n_angles.z > 180 || n_angles.z < -180) { n_angles.z = 0; } if (n_angles.x > -1 || n_angles.x < 1) { n_angles.x = 0; } if (n_angles.y > -1 || n_angles.y < 1) { n_angles.y = 0; } if (n_angles.z > -1 || n_angles.z < 1) { n_angles.z = 0; } avelocity = n_angles; for (last = this; last->vlink; last = v) { v = last->vlink; v->setOrigin(origin + i * v->offset.x + j * v->offset.y + k * v->offset.z); v->avelocity = avelocity; v->velocity = velocity; v->angles[ROLL] = angles[ROLL]; v->angles[YAW] = angles[YAW]; v->angles[PITCH] = (int)(drivespeed / 4.f + v->angles[PITCH]) % 360; v->setAngles(v->angles); } CheckWater(); WorldEffects(); last_origin = origin; if (!driver.ent && !velocity.length() && groundentity && !(watertype & CONTENTS_LAVA)) { // make the vehicle stationary if it's completely immobile flags &= ~FL_POSTTHINK; if (drivable) { setMoveType(MOVETYPE_STATIONARY); } } } void VehicleHalfTrack::Killed(Event *ev) { deadflag = DEAD_DEAD; }