mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
273 lines
6.5 KiB
C++
273 lines
6.5 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2025 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
|
|
===========================================================================
|
|
*/
|
|
|
|
// mover.cpp: Base class for any object that needs to move to specific locations over a
|
|
// period of time. This class is kept separate from most entities to keep
|
|
// class size down for objects that don't need such behavior.
|
|
//
|
|
|
|
#include "g_local.h"
|
|
#include "entity.h"
|
|
#include "trigger.h"
|
|
#include "mover.h"
|
|
#include "level.h"
|
|
#include "g_phys.h"
|
|
|
|
#define MOVE_ANGLES 1
|
|
#define MOVE_ORIGIN 2
|
|
|
|
CLASS_DECLARATION(Trigger, Mover, "mover") {
|
|
{&EV_MoveDone, &Mover::MoveDone},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
Mover::Mover()
|
|
{
|
|
endevent = NULL;
|
|
}
|
|
|
|
Mover::~Mover() {}
|
|
|
|
void Mover::MoveDone(Event *ev)
|
|
{
|
|
Event *event;
|
|
Vector move;
|
|
Vector amove;
|
|
|
|
// zero out the movement
|
|
avelocity = vec_zero;
|
|
if (moveflags & MOVE_ANGLES) {
|
|
amove = angledest - localangles;
|
|
} else {
|
|
amove = vec_zero;
|
|
}
|
|
|
|
velocity = vec_zero;
|
|
if (moveflags & MOVE_ORIGIN) {
|
|
move = finaldest - localorigin;
|
|
} else {
|
|
move = vec_zero;
|
|
}
|
|
|
|
accel = vec_zero;
|
|
aaccel = vec_zero;
|
|
|
|
if (!G_PushMove(this, move, amove)) {
|
|
// Added in OPM
|
|
// Check to make sure the event isn't pending
|
|
// blocked events called by G_PushMove() might alter
|
|
// the mover
|
|
if (!EventPending(EV_MoveDone)) {
|
|
// Delay finish till we can move into the final position
|
|
PostEvent(EV_MoveDone, FRAMETIME);
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// After moving, set origin to exact final destination
|
|
//
|
|
if (moveflags & MOVE_ORIGIN) {
|
|
setLocalOrigin(finaldest);
|
|
}
|
|
|
|
if (moveflags & MOVE_ANGLES) {
|
|
localangles = angledest;
|
|
|
|
if ((localangles.x >= 360) || (localangles.x < 0)) {
|
|
localangles.x -= ((int)localangles.x / 360) * 360;
|
|
}
|
|
if ((localangles.y >= 360) || (localangles.y < 0)) {
|
|
localangles.y -= ((int)localangles.y / 360) * 360;
|
|
}
|
|
if ((localangles.z >= 360) || (localangles.z < 0)) {
|
|
localangles.z -= ((int)localangles.z / 360) * 360;
|
|
}
|
|
}
|
|
|
|
event = endevent;
|
|
endevent = NULL;
|
|
|
|
if (event) {
|
|
ProcessEvent(event);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============
|
|
MoveTo
|
|
|
|
calculate self.velocity and self.nextthink to reach dest from
|
|
self.origin traveling at speed
|
|
===============
|
|
*/
|
|
void Mover::MoveTo(Vector tdest, Vector angdest, float tspeed, Event& event)
|
|
{
|
|
Vector vdestdelta;
|
|
Vector angdestdelta;
|
|
float len;
|
|
float traveltime;
|
|
|
|
assert(tspeed >= 0.0f);
|
|
|
|
if (!tspeed) {
|
|
error("MoveTo", "No speed is defined!");
|
|
}
|
|
|
|
if (tspeed < 0.0f) {
|
|
error("MoveTo", "Speed is negative!");
|
|
}
|
|
|
|
// Cancel previous moves
|
|
CancelEventsOfType(EV_MoveDone);
|
|
|
|
moveflags = 0;
|
|
|
|
if (endevent) {
|
|
delete endevent;
|
|
}
|
|
|
|
endevent = new Event(event);
|
|
|
|
finaldest = tdest;
|
|
angledest = angdest;
|
|
|
|
if (finaldest != localorigin) {
|
|
moveflags |= MOVE_ORIGIN;
|
|
}
|
|
if (angledest != localangles) {
|
|
moveflags |= MOVE_ANGLES;
|
|
}
|
|
|
|
if (!moveflags) {
|
|
// stop the object from moving
|
|
velocity = vec_zero;
|
|
avelocity = vec_zero;
|
|
|
|
// post the event so we don't wait forever
|
|
PostEvent(EV_MoveDone, FRAMETIME);
|
|
return;
|
|
}
|
|
|
|
// set destdelta to the vector needed to move
|
|
vdestdelta = tdest - localorigin;
|
|
angdestdelta[0] = angledist(angdest[0] - localangles[0]);
|
|
angdestdelta[1] = angledist(angdest[1] - localangles[1]);
|
|
angdestdelta[2] = angledist(angdest[2] - localangles[2]);
|
|
|
|
if (tdest == localorigin) {
|
|
// calculate length of vector based on angles
|
|
len = angdestdelta.length();
|
|
} else {
|
|
// calculate length of vector based on distance
|
|
len = vdestdelta.length();
|
|
}
|
|
|
|
// divide by speed to get time to reach dest
|
|
traveltime = len / tspeed;
|
|
|
|
if (traveltime < level.frametime) {
|
|
traveltime = level.frametime;
|
|
vdestdelta = vec_zero;
|
|
angdestdelta = vec_zero;
|
|
}
|
|
|
|
// scale the destdelta vector by the time spent traveling to get velocity
|
|
if (moveflags & MOVE_ORIGIN) {
|
|
velocity = vdestdelta * (1.0f / traveltime);
|
|
}
|
|
|
|
if (moveflags & MOVE_ANGLES) {
|
|
avelocity = angdestdelta * (1.0f / traveltime);
|
|
}
|
|
|
|
PostEvent(EV_MoveDone, traveltime);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
LinearInterpolate
|
|
===============
|
|
*/
|
|
void Mover::LinearInterpolate(Vector tdest, Vector angdest, float time, Event& event)
|
|
{
|
|
Vector vdestdelta;
|
|
Vector angdestdelta;
|
|
float t;
|
|
|
|
if (endevent) {
|
|
delete endevent;
|
|
}
|
|
endevent = new Event(event);
|
|
finaldest = tdest;
|
|
angledest = angdest;
|
|
|
|
// Cancel previous moves
|
|
CancelEventsOfType(EV_MoveDone);
|
|
|
|
// Quantize to FRAMETIME
|
|
if (time < FRAMETIME) {
|
|
time = FRAMETIME;
|
|
}
|
|
|
|
moveflags = 0;
|
|
t = 1 / time;
|
|
// scale the destdelta vector by the time spent traveling to get velocity
|
|
if (finaldest != localorigin) {
|
|
vdestdelta = tdest - localorigin;
|
|
velocity = vdestdelta * t;
|
|
moveflags |= MOVE_ORIGIN;
|
|
}
|
|
|
|
if (angledest != localangles) {
|
|
angdestdelta = angdest - localangles;
|
|
avelocity = angdestdelta * t;
|
|
moveflags |= MOVE_ANGLES;
|
|
}
|
|
|
|
if (g_bBeforeThinks) {
|
|
time -= FRAMETIME;
|
|
}
|
|
|
|
PostEvent(EV_MoveDone, time);
|
|
}
|
|
|
|
/*
|
|
=============
|
|
Stop
|
|
===============
|
|
*/
|
|
void Mover::Stop()
|
|
{
|
|
if (endevent) {
|
|
delete endevent;
|
|
endevent = NULL;
|
|
}
|
|
|
|
CancelEventsOfType(EV_MoveDone);
|
|
|
|
moveflags = 0;
|
|
avelocity = vec_zero;
|
|
velocity = vec_zero;
|
|
accel = vec_zero;
|
|
aaccel = vec_zero;
|
|
}
|