/** * @brief Slides a door * * @note Though doors, sliding doors need a very different handling: * because it's movement is animated (unlike the rotating door), * the final position that is used to calculate the routing data * is set once the animation finished (because this recalculation * might be very expensive). * * @param[in,out] le The local entity of the inline model * @param[in] speed The speed to slide with - a negative value to close the door * @sa Door_SlidingUse */ void LET_SlideDoor (le_t* le, int speed) { vec3_t moveAngles, moveDir; /* get the movement angle vector */ GET_SLIDING_DOOR_SHIFT_VECTOR(le->dir, speed, moveAngles); /* this origin is only an offset to the absolute mins/maxs for rendering */ VectorAdd(le->origin, moveAngles, le->origin); /* get the direction vector from the movement angles that were set on the entity */ AngleVectors(moveAngles, moveDir, nullptr, nullptr); moveDir[0] = fabsf(moveDir[0]); moveDir[1] = fabsf(moveDir[1]); moveDir[2] = fabsf(moveDir[2]); /* calculate the distance from the movement angles and the entity size */ const int distance = DotProduct(moveDir, le->size); bool endPos = false; if (speed > 0) { /* check whether the distance the door may slide is slided already * - if so, stop the movement of the door */ if (fabs(le->origin[le->dir & 3]) >= distance) endPos = true; } else { /* the sliding door has not origin set - except when it is opened. This door type is no * origin brush based bmodel entity. So whenever the origin vector is not the zero vector, * the door is opened. */ if (VectorEmpty(le->origin)) endPos = true; } if (endPos) { vec3_t distanceVec; /* the door finished its move - either close or open, so make sure to recalc the routing * data and set the mins/maxs for the inline brush model */ cBspModel_t* model = CM_InlineModel(cl.mapTiles, le->inlineModelName); assert(model); /* we need the angles vector normalized */ GET_SLIDING_DOOR_SHIFT_VECTOR(le->dir, (speed < 0) ? -1 : 1, moveAngles); /* the bounding box of the door is updated in one step - here is no lerping needed */ VectorMul(distance, moveAngles, distanceVec); model->cbmBox.shift(distanceVec); CL_RecalcRouting(le); /* reset the think function as the movement finished */ LE_SetThink(le, nullptr); } else le->thinkDelay = 1000; }
/** * @brief Slides a door * @note The new door state must already be set * @param[in,out] door The entity of the inline model. The aabb of this bmodel will get updated * in this function to reflect the new door position in the world * @sa LET_SlideDoor */ static void Door_SlidingUse (edict_t *door) { const bool open = door->doorState == STATE_OPENED; vec3_t moveAngles, moveDir, distanceVec; int distance; /* get the movement angle vector - a negative speed value will close the door*/ GET_SLIDING_DOOR_SHIFT_VECTOR(door->dir, open ? 1 : -1, moveAngles); /* get the direction vector from the movement angles that were set on the entity */ AngleVectors(moveAngles, moveDir, NULL, NULL); moveDir[0] = fabsf(moveDir[0]); moveDir[1] = fabsf(moveDir[1]); moveDir[2] = fabsf(moveDir[2]); /* calculate the distance from the movement angles and the entity size. This is the * distance the door has to slide to fully open or close */ distance = DotProduct(moveDir, door->size); /* the door is moved in one step on the server side - lerping is not needed here - so we * perform the scalar multiplication with the distance the door must move in order to * fully close/open */ VectorMul(distance, moveAngles, distanceVec); /* set the updated position. The bounding boxes that are used for tracing must be * shifted when the door state changes. As the mins and maxs of the aabb are absolute * world coordinates in the map we have to translate the position by the above * calculated movement vector */ VectorAdd(door->origin, distanceVec, door->origin); /* calc new model position */ // gi.SetInlineModelOrientation(door->model, door->origin, door->angles); /* move the model out of the way */ }