/** * @brief Moves actor. * @param[in] self Pointer to the event structure that is currently executed * @param[in] msg The netchannel message * @sa LET_PathMove * @note EV_ACTOR_MOVE */ void CL_ActorDoMove (const eventRegister_t* self, dbuffer* msg) { const int number = NET_ReadShort(msg); /* get le */ le_t* le = LE_Get(number); if (!le) LE_NotFoundError(number); if (!LE_IsActor(le)) Com_Error(ERR_DROP, "Can't move, LE doesn't exist or is not an actor (entnum: %i, type: %i)\n", number, le->type); if (LE_IsDead(le)) Com_Error(ERR_DROP, "Can't move, actor on team %i dead (entnum: %i)", le->team, number); /* lock this le for other events, the corresponding unlock is in LE_DoEndPathMove() */ LE_Lock(le); if (le->isMoving()) { if (le->pathLength == le->pathPos) { LE_DoEndPathMove(le); } else { Com_Error(ERR_DROP, "Actor (entnum: %i) on team %i is still moving (%i steps left). Times: %i, %i, %i", le->entnum, le->team, le->pathLength - le->pathPos, le->startTime, le->endTime, cl.time); } } int i = 0; /* the end of this event is marked with a 0 */ while (NET_PeekLong(msg) != 0) { NET_ReadByte(msg); le->dvtab[i] = NET_ReadShort(msg); /** Don't adjust dv values here- the whole thing is needed to move the actor! */ le->speed[i] = NET_ReadShort(msg); le->pathContents[i] = NET_ReadShort(msg); i++; } le->pathLength = i; if (le->pathLength > MAX_ROUTE) Com_Error(ERR_DROP, "Overflow in pathLength (entnum: %i)", number); /* skip the end of move marker */ NET_ReadLong(msg); /* Also get the final position */ NET_ReadGPos(msg, le->newPos); if (VectorCompare(le->newPos, le->pos)) Com_Error(ERR_DROP, "start and end pos are the same (entnum: %i)", number); /* activate PathMove function */ le->resetFloor(); if (LE_IsInvisible(le)) /* Hack: this relies on the visibility events interrupting the EV_ACTOR_MOVE event */ LE_SetThink(le, LET_HiddenMove); else LE_SetThink(le, LET_StartPathMove); le->pathPos = 0; le->startTime = cl.time; le->endTime = cl.time; }
/** * @brief Move the actor along the path to the given location * @note Think function * @sa CL_ActorDoMove */ static void LET_PathMove (le_t* le) { /* check for start of the next step */ if (cl.time < le->startTime) return; /* move ahead */ while (cl.time >= le->endTime) { /* Ensure that we are displayed where we are supposed to be, in case the last frame came too quickly. */ Grid_PosToVec(cl.mapData->routing, le->fieldSize, le->pos, le->origin); /* Record the last position of movement calculations. */ VectorCopy(le->pos, le->oldPos); if (le->pathPos < le->pathLength) { LE_DoPathMove(le); } else { LE_DoEndPathMove(le); return; } } /* interpolate the position */ vec3_t start, dest, delta; Grid_PosToVec(cl.mapData->routing, le->fieldSize, le->oldPos, start); Grid_PosToVec(cl.mapData->routing, le->fieldSize, le->pos, dest); VectorSubtract(dest, start, delta); const float frac = (float) (cl.time - le->startTime) / (float) (le->endTime - le->startTime); /* calculate the new interpolated actor origin in the world */ VectorMA(start, frac, delta, le->origin); }