/** * @brief Callback for EV_DOOR_CLOSE event - rotates the inline model and recalc routing * @sa EV_DOOR_CLOSE * @sa G_ClientUseEdict * @sa Touch_DoorTrigger */ void CL_DoorClose (const eventRegister_t *self, struct dbuffer *msg) { /* get local entity */ int number; le_t *le; NET_ReadFormat(msg, self->formatString, &number); le = LE_Get(number); if (!le) LE_NotFoundError(number); if (le->type == ET_DOOR) { if (le->dir & DOOR_OPEN_REVERSE) le->angles[le->dir & 3] += DOOR_ROTATION_ANGLE; else le->angles[le->dir & 3] -= DOOR_ROTATION_ANGLE; CM_SetInlineModelOrientation(cl.mapTiles, le->inlineModelName, le->origin, le->angles); CL_RecalcRouting(le); } else if (le->type == ET_DOOR_SLIDING) { LE_SetThink(le, LET_DoorSlidingClose); le->think(le); } else { Com_Error(ERR_DROP, "Invalid door entity found of type: %i", le->type); } }
/** * @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; }
/** * @note e.g. func_breakable or func_door with health * @sa EV_MODEL_EXPLODE */ void CL_Explode (const eventRegister_t *self, struct dbuffer *msg) { const int entnum = NET_ReadShort(msg); le_t *le = LE_Get(entnum); if (!le) LE_NotFoundError(entnum); le->inuse = false; if (le->modelnum1 > 0) cl.model_clip[le->modelnum1] = NULL; /* Recalc the client routing table because this le (and the inline model) is now gone */ CL_RecalcRouting(le); }
/** * @brief Rotates a door in the given speed * * @param[in] le The local entity of the door to rotate * @param[in] speed The speed to rotate the door with */ void LET_RotateDoor (le_t* le, int speed) { /** @todo lerp the rotation */ const int angle = speed > 0 ? DOOR_ROTATION_ANGLE : -DOOR_ROTATION_ANGLE; if (le->dir & DOOR_OPEN_REVERSE) le->angles[le->dir & 3] -= angle; else le->angles[le->dir & 3] += angle; CM_SetInlineModelOrientation(cl.mapTiles, le->inlineModelName, le->origin, le->angles); CL_RecalcRouting(le); /* reset the think function as the movement finished */ LE_SetThink(le, nullptr); }
/** * @brief Register local entities for SOLID_BSP models like func_breakable or func_door * @note func_breakable, func_door * @sa G_SendEdictsAndBrushModels * @sa EV_ADD_BRUSH_MODEL * @sa CL_SpawnParseEntitystring */ void CL_AddBrushModel (const eventRegister_t *self, struct dbuffer *msg) { le_t *le; int entnum, modelnum1, levelflags, speed, dir; entity_type_t type; const cBspModel_t *model; int angle; vec3_t origin, angles; NET_ReadFormat(msg, self->formatString, &type, &entnum, &modelnum1, &levelflags, &origin, &angles, &speed, &angle, &dir); if (type != ET_BREAKABLE && type != ET_DOOR && type != ET_ROTATING && type != ET_DOOR_SLIDING && type != ET_TRIGGER_RESCUE && type != ET_TRIGGER_NEXTMAP) Com_Error(ERR_DROP, "Invalid le announced via EV_ADD_BRUSH_MODEL type: %i\n", type); else if (modelnum1 > MAX_MODELS || modelnum1 < 1) Com_Error(ERR_DROP, "Invalid le modelnum1 announced via EV_ADD_BRUSH_MODEL\n"); /* check if the ent is already visible */ le = LE_Get(entnum); if (le) Com_Error(ERR_DROP, "le announced a second time - le for entnum %i (type: %i) already exists (via EV_ADD_BRUSH_MODEL)\n", entnum, type); le = LE_Add(entnum); assert(le); le->rotationSpeed = speed / 100.0f; le->slidingSpeed = speed; le->angle = angle; le->dir = dir; le->type = type; le->modelnum1 = modelnum1; le->levelflags = levelflags; le->addFunc = LE_BrushModelAction; LE_SetThink(le, LET_BrushModel); /* The origin and angles are REQUIRED for doors to work! */ VectorCopy(origin, le->origin); /* store the initial position - needed for sliding doors */ VectorCopy(le->origin, le->oldOrigin); VectorCopy(angles, le->angles); Com_sprintf(le->inlineModelName, sizeof(le->inlineModelName), "*%i", le->modelnum1); model = LE_GetClipModel(le); le->model1 = R_FindModel(le->inlineModelName); if (!le->model1) Com_Error(ERR_DROP, "CL_AddBrushModel: Could not register inline model %i", le->modelnum1); /* Transfer model mins and maxs to entity */ VectorCopy(model->mins, le->mins); VectorCopy(model->maxs, le->maxs); VectorSubtract(le->maxs, le->mins, le->size); VecToPos(le->origin, le->pos); /* to allow tracing against this le */ if (!LE_IsNotSolid(le)) { /* This is to help the entity collision code out */ /* Copy entity origin and angles to model*/ CM_SetInlineModelOrientation(cl.mapTiles, le->inlineModelName, le->origin, le->angles); le->contents = CONTENTS_SOLID; CL_RecalcRouting(le); } }