/* tests for the new dvec format */ static void testDvec (void) { short dv1 = 0x0724; CU_ASSERT_EQUAL(getDVdir(dv1), 0x07); CU_ASSERT_EQUAL(getDVflags(dv1), 0x02); CU_ASSERT_EQUAL(getDVz(dv1), 0x04); short dv2 = makeDV(6, 3); CU_ASSERT_EQUAL(dv2, 0x0603); dv2 = setDVz(dv2, 4); CU_ASSERT_EQUAL(dv2, 0x0604); }
/** * @brief Checks if we can walk in the given direction * First test for opening height availability. Then test for stepup compatibility. Last test for fall. * @note Fliers use this code only when they are walking. * @param[in] path Pointer to client or server side pathing table (clPathMap, svPathMap) * @return false if we can't fly there */ bool Step::checkWalkingDirections (const pathing_t *path) { int nx, ny, nz; int passageHeight; /** @todo falling_height should be replaced with an arbitrary max falling height based on the actor. */ const int fallingHeight = PATHFINDING_MAX_FALL;/**<This is the maximum height that an actor can fall. */ const int stepupHeight = routing.getStepupHeight(actorSize, fromPos[0], fromPos[1], fromPos[2], dir); /**< The actual stepup height without the level flags */ int heightChange; /** @todo actor_stepup_height should be replaced with an arbitrary max stepup height based on the actor. */ int actorStepupHeight = PATHFINDING_MAX_STEPUP; /* This is the standard passage height for all units trying to move horizontally. */ passageHeight = routing.getConn(actorSize, fromPos, dir); if (passageHeight < actorHeight) { #if 0 /** I know this code could be streamlined, but until I understand it myself, plz leave it like it is !*/ int dvFlagsNew = 0; if (!crouchingState /* not in std crouch mode */ && passageHeight >= actorCrouchedHeight) { /* and passage is tall enough for crouching ? */ /* we should try autocrouching */ int dvFlagsOld = getDVflags(RT_AREA_POS(path, fromPos, crouchingState)); int toHeight = routing.getCeiling(actorSize, toPos) - routing.getFloor(actorSize, toPos); int tuCr = Grid_GetTUsForDirection(dir, 1); /* 1 means crouched */ int newTUs = 0; if (toHeight >= actorHeight) { /* can we stand in the new cell ? */ if ((dvFlagsOld & DV_FLAG_AUTOCROUCH) /* already in auto-crouch mode ? */ || (dvFlagsOld & DV_FLAG_AUTOCROUCHED)) { dvFlagsNew |= DV_FLAG_AUTOCROUCHED; /* keep that ! */ newTUs = tuCr + TU_CROUCH; /* TUs for crouching plus getting up */ } else { dvFlagsNew |= DV_FLAG_AUTODIVE; newTUs = tuCr + 2 * TU_CROUCH; /* TUs for crouching plus getting down and up */ } } else { /* we can't stand there */ if (dvFlagsOld & DV_FLAG_AUTOCROUCHED) { dvFlagsNew |= DV_FLAG_AUTOCROUCHED; /* keep that ! */ newTUs = tuCr; /* TUs just for crouching */ } else { dvFlagsNew |= DV_FLAG_AUTOCROUCH; /* get down ! */ newTUs = tuCr + TU_CROUCH; /* TUs for crouching plus getting down */ } } } else #endif return false; /* Passage is not tall enough. */ } /* If we are moving horizontally, use the stepup requirement of the floors. * The new z coordinate may need to be adjusted from stepup. * Also, actor_stepup_height must be at least the cell's positive stepup value to move that direction. */ /* If the actor cannot reach stepup, then we can't go this way. */ if (actorStepupHeight < stepupHeight) { return false; /* Actor cannot stepup high enough. */ } nx = toPos[0]; ny = toPos[1]; nz = toPos[2]; if (routing.isStepUpLevel(actorSize, fromPos, dir) && toPos[2] < PATHFINDING_HEIGHT - 1) { toPos[2]++; /** * @note If you need to know about how pathfinding works, you need to understand the * following brief. It may cause nausea, but is an important concept. * * @brief OK, now some crazy tests: * Because of the grid based nature of this game, each cell can have at most only ONE * floor that can be stood upon. If an actor can walk down a slope that is in the * same level, and actor should be able to walk on (and not fall into) the slope that * decends a game level. BUT it is possible for an actor to be able to crawl under a * floor that can be stood on, with this opening being in the same cell as the floor. * SO to prevent any conflicts, we will move down a floor under the following conditions: * - The STEPDOWN flag is set * - The floor in the immediately adjacent cell is lower than the current floor, but not * more than CELL_HEIGHT units (in QUANT units) below the current floor. * - The actor's stepup value is at least the inverse stepup value. This is the stepup * FROM the cell we are moving towards back into the cell we are starting in. This * ensures that the actor can actually WALK BACK. * If the actor does not have a high enough stepup but meets all the other requirements to * descend the level, the actor will move into a fall state, provided that there is no * floor in the adjacent cell. * * This will prevent actors from walking under a floor in the same cell in order to fall * to the floor beneath. They will need to be able to step down into the cell or will * not be able to use the opening. */ } else if (routing.isStepDownLevel(actorSize, fromPos, dir) && toPos[2] > 0 && actorStepupHeight >= routing.getStepupHeight(actorSize, nx, ny, nz - 1, dir ^ 1)) { toPos[2]--; /* Stepping down into lower cell. */ } heightChange = routing.getFloor(actorSize, toPos) - routing.getFloor(actorSize, fromPos) + (toPos[2] - fromPos[2]) * CELL_HEIGHT; /* If the actor tries to fall more than falling_height, then prohibit the move. */ if (heightChange < -fallingHeight && !hasLadderSupport) { return false; /* Too far a drop without a ladder. */ } /* If we are walking normally, we can fall if we move into a cell that does not * have its STEPDOWN flag set and has a negative floor: * Set heightChange to 0. * The actor enters the cell. * The actor will be forced to fall (dir 13) from the destination cell to the cell below. */ if (routing.getFloor(actorSize, toPos) < 0) { /* We cannot fall if STEPDOWN is defined. */ if (routing.isStepDownLevel(actorSize, fromPos, dir)) { return false; /* There is stepdown from here. */ } heightChange = 0; toPos[2]--; } return true; }