diff -ruN ../src_orig/Battlescape/Pathfinding.cpp ../src_new2/Battlescape/Pathfinding.cpp --- ../src_orig/Battlescape/Pathfinding.cpp Mon Oct 17 19:36:12 2016 +++ ../src_new2/Battlescape/Pathfinding.cpp Wed Oct 26 06:16:16 2016 @@ -236,6 +238,17 @@ return false; } +void Pathfinding::incDoorWallCost(Tile *tile, int part, int *wallcost, int *doorcost, int direction) +{ + if (!tile->getMapData(part)) return; + if (tile->getMapData(part)->isDoor() && (direction & 1)) return; //skip hinged + if (!tile->getMapData(part)->isUFODoor()) //non ufo doors, i.e. walls + *wallcost += tile->getTUCost(part, _movementType); + else + if (tile->isUfoDoorClosed(part)) //only closed door, semiclosed aren't affecting + *doorcost += tile->getTUCost(part, _movementType); +} + /** * Gets the TU cost to move from 1 tile to the other (ONE STEP ONLY). * But also updates the endPosition, because it is possible @@ -262,6 +275,8 @@ int numberOfPartsFalling = 0; int numberOfPartsChangingHeight = 0; int totalCost = 0; + int wallcost = 0; + int doorcost = 0; for (int x = 0; x <= size; ++x) for (int y = 0; y <= size; ++y) @@ -380,25 +395,141 @@ return 255; } - int wallcost = 0; // walking through rubble walls, but don't charge for walking diagonally through doors (which is impossible), - // they're a special case unto themselves, if we can walk past them diagonally, it means we can go around, - // as there is no wall blocking us. - if (direction == 0 || direction == 7 || direction == 1) - wallcost += startTile->getTUCost(O_NORTHWALL, _movementType); - if (!fellDown && (direction == 2 || direction == 1 || direction == 3)) - wallcost += destinationTile->getTUCost(O_WESTWALL, _movementType); - if (!fellDown && (direction == 4 || direction == 3 || direction == 5)) - wallcost += destinationTile->getTUCost(O_NORTHWALL, _movementType); - if (direction == 6 || direction == 5 || direction == 7) - wallcost += startTile->getTUCost(O_WESTWALL, _movementType); - // don't let tanks phase through doors. - if (x && y) - { - if ((destinationTile->getMapData(O_NORTHWALL) && destinationTile->getMapData(O_NORTHWALL)->isDoor()) || - (destinationTile->getMapData(O_WESTWALL) && destinationTile->getMapData(O_WESTWALL)->isDoor())) - { - return 255; + Tile *startEastTile = _save->getTile(startPosition + offset + Position(1,0,0)); + Tile *startSouthTile = _save->getTile(startPosition + offset + Position(0,1,0)); + Tile *startWestTile = _save->getTile(startPosition + offset + Position(-1,0,0)); + Tile *startNorthTile = _save->getTile(startPosition + offset + Position(0,-1,0)); + Tile *startNorthEastTile = _save->getTile(startPosition + offset + Position(1,-1,0)); + Tile *startSouthWestTile = _save->getTile(startPosition + offset + Position(-1,1,0)); + if (!fellDown) + { + switch (direction) + { + case 0: + if (x == 0) + incDoorWallCost(startTile, O_NORTHWALL, &wallcost, &doorcost, direction); + else + { + incDoorWallCost(destinationTile, O_WESTWALL, &wallcost, &doorcost, direction); + if (!startTile->isUfoDoorClosed(O_NORTHWALL) || !startWestTile->isUfoDoorClosed(O_NORTHWALL)) //west of x>0 should present + incDoorWallCost(startTile, O_NORTHWALL, &wallcost, &doorcost, direction); + } + break; + case 1: + incDoorWallCost(startTile, O_NORTHWALL, &wallcost, &doorcost, direction); // north + incDoorWallCost(destinationTile, O_WESTWALL, &wallcost, &doorcost, direction); // west wall of northeast + if (startEastTile) + { + // do not make additional charge for the second segment of adjacent closed door when passing diagonally + if (!startTile->isUfoDoorClosed(O_NORTHWALL) || !startEastTile->isUfoDoorClosed(O_NORTHWALL)) + incDoorWallCost(startEastTile, O_NORTHWALL, &wallcost, &doorcost, direction); //north wall of east + if (!destinationTile->isUfoDoorClosed(O_WESTWALL) || !startEastTile->isUfoDoorClosed(O_WESTWALL)) + incDoorWallCost(startEastTile, O_WESTWALL, &wallcost, &doorcost, direction); //west wall of east + } + break; + case 2: + if (y == 0) + incDoorWallCost(destinationTile, O_WESTWALL, &wallcost, &doorcost, direction); + else + { + incDoorWallCost(destinationTile, O_NORTHWALL, &wallcost, &doorcost, direction); + if (!destinationTile->isUfoDoorClosed(O_WESTWALL) || (startNorthEastTile && !startNorthEastTile->isUfoDoorClosed(O_WESTWALL))) + incDoorWallCost(destinationTile, O_WESTWALL, &wallcost, &doorcost, direction); + } + break; + case 3: + incDoorWallCost(destinationTile, O_NORTHWALL, &wallcost, &doorcost, direction); //north wall of southeast + incDoorWallCost(destinationTile, O_WESTWALL, &wallcost, &doorcost, direction); //west wall of southeast + if (startSouthTile) + if (!destinationTile->isUfoDoorClosed(O_NORTHWALL) || !startSouthTile->isUfoDoorClosed(O_NORTHWALL)) + incDoorWallCost(startSouthTile, O_NORTHWALL, &wallcost, &doorcost, direction); //north wall of south + if (startEastTile) + if (!destinationTile->isUfoDoorClosed(O_WESTWALL) || !startEastTile->isUfoDoorClosed(O_WESTWALL)) + incDoorWallCost(startEastTile, O_WESTWALL, &wallcost, &doorcost, direction); //west wall of east + break; + case 4: + if (x == 0) + incDoorWallCost(destinationTile, O_NORTHWALL, &wallcost, &doorcost, direction); + else + { + incDoorWallCost(destinationTile, O_WESTWALL, &wallcost, &doorcost, direction); + if (!destinationTile->isUfoDoorClosed(O_NORTHWALL) || (startSouthWestTile && !startSouthWestTile->isUfoDoorClosed(O_NORTHWALL))) + incDoorWallCost(destinationTile, O_NORTHWALL, &wallcost, &doorcost, direction); + } + break; + case 5: + incDoorWallCost(destinationTile, O_NORTHWALL, &wallcost, &doorcost, direction); //north wall of southwest + incDoorWallCost(startTile, O_WESTWALL, &wallcost, &doorcost, direction); // west + if (startSouthTile) + { + if (!destinationTile->isUfoDoorClosed(O_NORTHWALL) || !startSouthTile->isUfoDoorClosed(O_NORTHWALL)) + incDoorWallCost(startSouthTile, O_NORTHWALL, &wallcost, &doorcost, direction); //north wall of south + if (!startTile->isUfoDoorClosed(O_WESTWALL) || !startSouthTile->isUfoDoorClosed(O_WESTWALL)) + incDoorWallCost(startSouthTile, O_WESTWALL, &wallcost, &doorcost, direction); //west fall of south + } + break; + case 6: + if (y == 0) + incDoorWallCost(startTile, O_WESTWALL, &wallcost, &doorcost, direction); + else + { + incDoorWallCost(destinationTile, O_NORTHWALL, &wallcost, &doorcost, direction); + if (!startTile->isUfoDoorClosed(O_WESTWALL) || !startNorthTile->isUfoDoorClosed(O_WESTWALL)) //north of y>0 should present + incDoorWallCost(startTile, O_WESTWALL, &wallcost, &doorcost, direction); + } + break; + case 7: + incDoorWallCost(startTile, O_WESTWALL, &wallcost, &doorcost, direction); // west + incDoorWallCost(startTile, O_NORTHWALL, &wallcost, &doorcost, direction); // north + if (startWestTile) + if (!startTile->isUfoDoorClosed(O_NORTHWALL) || !startWestTile->isUfoDoorClosed(O_NORTHWALL)) + incDoorWallCost(startWestTile, O_NORTHWALL, &wallcost, &doorcost, direction); //north wall of south + if (startNorthTile) + if (!startTile->isUfoDoorClosed(O_WESTWALL) || !startNorthTile->isUfoDoorClosed(O_WESTWALL)) + incDoorWallCost(startNorthTile, O_WESTWALL, &wallcost, &doorcost, direction); //west wall of north + break; + } + } + // don't let tanks phase through hinged doors. + if (size>0) + { + switch (direction) + { + case 0: + if (x>0 && destinationTile->getMapData(O_WESTWALL) && destinationTile->getMapData(O_WESTWALL)->isDoor() ) + return 255; + if (startTile->getMapData(O_NORTHWALL) && startTile->getMapData(O_NORTHWALL)->isDoor() ) + return 255; + break; + case 2: + if (y>0 && destinationTile->getMapData(O_NORTHWALL) && destinationTile->getMapData(O_NORTHWALL)->isDoor() ) + return 255; + if (destinationTile->getMapData(O_WESTWALL) && destinationTile->getMapData(O_WESTWALL)->isDoor() ) + return 255; + break; + case 4: + if (x>0 && destinationTile->getMapData(O_WESTWALL) && destinationTile->getMapData(O_WESTWALL)->isDoor() ) + return 255; + if (destinationTile->getMapData(O_NORTHWALL) && destinationTile->getMapData(O_NORTHWALL)->isDoor() ) + return 255; + break; + case 6: + if (y>0 && destinationTile->getMapData(O_NORTHWALL) && destinationTile->getMapData(O_NORTHWALL)->isDoor() ) + return 255; + if (startTile->getMapData(O_WESTWALL) && startTile->getMapData(O_WESTWALL)->isDoor() ) + return 255; + break; + case 1: + case 3: + case 5: + case 7: + if (x>0 && destinationTile->getMapData(O_WESTWALL) && destinationTile->getMapData(O_WESTWALL)->isDoor() ) + return 255; + if (y>0 && destinationTile->getMapData(O_NORTHWALL) && destinationTile->getMapData(O_NORTHWALL)->isDoor() ) + return 255; + break; } + } // check if the destination tile can be walked over if (isBlocked(destinationTile, O_FLOOR, target) || isBlocked(destinationTile, O_OBJECT, target)) @@ -429,10 +560,8 @@ // diagonal walking (uneven directions) costs 50% more tu's if (direction < DIR_UP && direction & 1) { - wallcost /= 2; cost = (int)((double)cost * 1.5); } - cost += wallcost; if (_unit->getFaction() != FACTION_PLAYER && _unit->getSpecialAbility() < SPECAB_BURNFLOOR && destinationTile->getFire() > 0) @@ -469,6 +598,14 @@ totalCost += cost; cost = 0; } + + if (direction < DIR_UP && direction & 1) + { + wallcost = (int)((double)wallcost * 1.5 * 0.5); //diagonal, thus avaraged between both parts +// doorcost = (int)((double)doorcost * 1.5); + } + totalCost += wallcost; + totalCost += doorcost * (size+1)*(size+1); //doors can be opened once even for bigunits // for bigger sized units, check the path between parts in an X shape at the end position if (size) diff -ruN ../src_orig/Battlescape/Pathfinding.h ../src_new2/Battlescape/Pathfinding.h --- ../src_orig/Battlescape/Pathfinding.h Mon Oct 17 19:36:12 2016 +++ ../src_new2/Battlescape/Pathfinding.h Wed Oct 26 05:07:07 2016 @@ -83,6 +83,8 @@ int getStartDirection() const; /// Dequeues a direction. int dequeuePath(); + /// Increase TU cost to move from 1 tile to other specifically for walls/doors. + void incDoorWallCost(Tile *tile, int part, int *wallcost, int *doorcost, int direction); /// Gets the TU cost to move from 1 tile to the other. int getTUCost(const Position &startPosition, int direction, Position *endPosition, BattleUnit *unit, BattleUnit *target, bool missile); /// Aborts the current path. diff -ruN ../src_orig/Battlescape/TileEngine.cpp ../src_new2/Battlescape/TileEngine.cpp --- ../src_orig/Battlescape/TileEngine.cpp Mon Oct 17 19:36:12 2016 +++ ../src_new2/Battlescape/TileEngine.cpp Wed Oct 26 05:38:20 2016 @@ -1929,45 +1956,42 @@ { case 0: // north checkPositions.push_back(std::make_pair(Position(0, 0, 0), O_NORTHWALL)); // origin - if (x != 0) + if (x != 0) //bigunit walks through parallel door { checkPositions.push_back(std::make_pair(Position(0, -1, 0), O_WESTWALL)); // one tile north } break; case 1: // north east checkPositions.push_back(std::make_pair(Position(0, 0, 0), O_NORTHWALL)); // origin + checkPositions.push_back(std::make_pair(Position(1, 0, 0), O_WESTWALL)); // one tile east checkPositions.push_back(std::make_pair(Position(1, -1, 0), O_WESTWALL)); // one tile north-east - if (rClick) - { - checkPositions.push_back(std::make_pair(Position(1, 0, 0), O_WESTWALL)); // one tile east - checkPositions.push_back(std::make_pair(Position(1, 0, 0), O_NORTHWALL)); // one tile east - } + checkPositions.push_back(std::make_pair(Position(1, 0, 0), O_NORTHWALL)); // one tile east break; case 2: // east checkPositions.push_back(std::make_pair(Position(1, 0, 0), O_WESTWALL)); // one tile east - break; - case 3: // south-east - if (!y) - checkPositions.push_back(std::make_pair(Position(1, 1, 0), O_WESTWALL)); // one tile south-east - if (!x) - checkPositions.push_back(std::make_pair(Position(1, 1, 0), O_NORTHWALL)); // one tile south-east - if (rClick) + if (y != 0) { - checkPositions.push_back(std::make_pair(Position(1, 0, 0), O_WESTWALL)); // one tile east - checkPositions.push_back(std::make_pair(Position(0, 1, 0), O_NORTHWALL)); // one tile south + checkPositions.push_back(std::make_pair(Position(1, 0, 0), O_NORTHWALL)); // one tile east } break; + case 3: // south-east + checkPositions.push_back(std::make_pair(Position(1, 0, 0), O_WESTWALL)); // one tile east + checkPositions.push_back(std::make_pair(Position(0, 1, 0), O_NORTHWALL)); // one tile south + checkPositions.push_back(std::make_pair(Position(1, 1, 0), O_NORTHWALL)); // one tile south-east + checkPositions.push_back(std::make_pair(Position(1, 1, 0), O_WESTWALL)); // one tile south-east + break; case 4: // south checkPositions.push_back(std::make_pair(Position(0, 1, 0), O_NORTHWALL)); // one tile south + if (x != 0) + { + checkPositions.push_back(std::make_pair(Position(0, 1, 0), O_WESTWALL)); // one tile south + } break; case 5: // south-west checkPositions.push_back(std::make_pair(Position(0, 0, 0), O_WESTWALL)); // origin + checkPositions.push_back(std::make_pair(Position(0, 1, 0), O_NORTHWALL)); // one tile south checkPositions.push_back(std::make_pair(Position(-1, 1, 0), O_NORTHWALL)); // one tile south-west - if (rClick) - { - checkPositions.push_back(std::make_pair(Position(0, 1, 0), O_WESTWALL)); // one tile south - checkPositions.push_back(std::make_pair(Position(0, 1, 0), O_NORTHWALL)); // one tile south - } + checkPositions.push_back(std::make_pair(Position(0, 1, 0), O_WESTWALL)); // one tile south break; case 6: // west checkPositions.push_back(std::make_pair(Position(0, 0, 0), O_WESTWALL)); // origin @@ -1979,19 +2003,8 @@ case 7: // north-west checkPositions.push_back(std::make_pair(Position(0, 0, 0), O_WESTWALL)); // origin checkPositions.push_back(std::make_pair(Position(0, 0, 0), O_NORTHWALL)); // origin - if (x) - { - checkPositions.push_back(std::make_pair(Position(-1, -1, 0), O_WESTWALL)); // one tile north - } - if (y) - { - checkPositions.push_back(std::make_pair(Position(-1, -1, 0), O_NORTHWALL)); // one tile north - } - if (rClick) - { - checkPositions.push_back(std::make_pair(Position(0, -1, 0), O_WESTWALL)); // one tile north - checkPositions.push_back(std::make_pair(Position(-1, 0, 0), O_NORTHWALL)); // one tile west - } + checkPositions.push_back(std::make_pair(Position(-1, 0, 0), O_NORTHWALL)); // one tile west + checkPositions.push_back(std::make_pair(Position(0, -1, 0), O_WESTWALL)); // one tile north break; default: break; @@ -2001,39 +2014,34 @@ for (std::vector >::const_iterator i = checkPositions.begin(); i != checkPositions.end() && door == -1; ++i) { tile = _save->getTile(unit->getPosition() + Position(x,y,z) + i->first); - if (tile) + part = i->second; + if (tile && tile->getMapData(part) && (tile->getMapData(part)->isDoor() || tile->getMapData(part)->isUFODoor())) { - door = tile->openDoor(i->second, unit, _save->getBattleGame()->getReservedAction()); - if (door != -1) - { - part = i->second; - if (door == 1) + TUCost = tile->getTUCost(part, unit->getMovementType()); + if (dir & 1) { - checkAdjacentDoors(unit->getPosition() + Position(x,y,z) + i->first, i->second); + if (tile->getMapData(part)->isDoor() && !rClick) //skip diagonal hinged doors except for rClick + { + TUCost = 0; + door = -1; + continue; + } + else + { +// TUCost = (int)((double)TUCost * 1.5); //diagonal ufodoor open + } } + door = tile->openDoor(part, TUCost, unit, _save->getBattleGame()->getReservedAction()); + if (door == 1) + { + checkAdjacentDoors(unit->getPosition() + Position(x,y,z) + i->first, part); } } } - if (door == 0 && rClick) - { - if (part == O_WESTWALL) - { - part = O_NORTHWALL; - } - else - { - part = O_WESTWALL; - } - TUCost = tile->getTUCost(part, unit->getMovementType()); - } - else if (door == 1 || door == 4) - { - TUCost = tile->getTUCost(part, unit->getMovementType()); - } } } - if (TUCost != 0) + if (TUCost != 0 && (door == 1 || (rClick && door == 0))) { if (_save->getBattleGame()->checkReservedTU(unit, TUCost)) { diff -ruN ../src_orig/Savegame/Tile.cpp ../src_new2/Savegame/Tile.cpp --- ../src_orig/Savegame/Tile.cpp Mon Oct 17 19:36:12 2016 +++ ../src_new2/Savegame/Tile.cpp Wed Oct 26 00:26:36 2016 @@ -330,17 +330,18 @@ /** * Open a door on this tile. * @param part - * @param unit - * @param reserve + * @param TUcost default 0 + * @param unit deafult 0 + * @param reserve default 0 * @return a value: 0(normal door), 1(ufo door) or -1 if no door opened or 3 if ufo door(=animated) is still opening 4 if not enough TUs */ -int Tile::openDoor(int part, BattleUnit *unit, BattleActionType reserve) +int Tile::openDoor(int part, int TUcost, BattleUnit *unit, BattleActionType reserve) { if (!_objects[part]) return -1; if (_objects[part]->isDoor() && unit->getArmor()->getSize() == 1) // don't allow double-wide units to open swinging doors due to engine limitations { - if (unit && unit->getTimeUnits() < _objects[part]->getTUCost(unit->getMovementType()) + unit->getActionTUs(reserve, unit->getMainHandWeapon(false))) + if (unit && unit->getTimeUnits() < TUcost + unit->getActionTUs(reserve, unit->getMainHandWeapon(false))) return 4; if (_unit && _unit != unit && _unit->getPosition() != getPosition()) return -1; @@ -351,7 +352,7 @@ } if (_objects[part]->isUFODoor() && _currentFrame[part] == 0) // ufo door part 0 - door is closed { - if (unit && unit->getTimeUnits() < _objects[part]->getTUCost(unit->getMovementType()) + unit->getActionTUs(reserve, unit->getMainHandWeapon(false))) + if (unit && unit->getTimeUnits() < TUcost + unit->getActionTUs(reserve, unit->getMainHandWeapon(false))) return 4; _currentFrame[part] = 1; // start opening door return 1; diff -ruN ../src_orig/Savegame/Tile.h ../src_new2/Savegame/Tile.h --- ../src_orig/Savegame/Tile.h Mon Oct 17 19:36:12 2016 +++ ../src_new2/Savegame/Tile.h Wed Oct 26 00:26:36 2016 @@ -130,7 +130,7 @@ /// Gets the floor object footstep sound. int getFootstepSound(Tile *tileBelow) const; /// Open a door, returns the ID, 0(normal), 1(ufo) or -1 if no door opened. - int openDoor(int part, BattleUnit *Unit = 0, BattleActionType reserve = BA_NONE); + int openDoor(int part, int TUcost = 0, BattleUnit *Unit = 0, BattleActionType reserve = BA_NONE); /** * Check if the ufo door is open or opening. Used for visibility/light blocking checks. @@ -141,6 +141,16 @@ bool isUfoDoorOpen(int part) const { return (_objects[part] && _objects[part]->isUFODoor() && _currentFrame[part] != 0); + } + + /** + * Check if the ufo door is closed. Used for pathfinding. + * @param part + * @return bool + */ + bool isUfoDoorClosed(int part) const + { + return (_objects[part] && _objects[part]->isUFODoor() && _currentFrame[part] == 0); } /// Close ufo door.