void World::move(zf::Direction direction) { if (player and player->canMove()) { if (player->isGrabbing()) { auto mod = zf::getModifier(direction); auto playerTargetPosition = player->position + mod; bool canMove = true; if (inRange(playerTargetPosition)) { auto grabbed = player->getGrabbedObjects(); auto destinationObject = getObject(playerTargetPosition); if (!destinationObject || std::find(grabbed.begin(), grabbed.end(), destinationObject) != grabbed.end()) { for (auto object : grabbed) { if (!object->canGrabbed(direction, *player, grabbed)) { canMove = false; break; } } if (canMove) { moveObject(*player, player->position + mod); player->objectMoved(); for (auto object : grabbed) { moveObject (*object, object->position + mod); } player->doWork(game.balance.Player_MoveCost + grabbed.size() * game.balance.Player_GrabCost); } } } } else { auto mod = zf::getModifier(direction); auto targetPosition = player->position + mod; if (inRange(targetPosition)) { auto object = getObject(targetPosition); auto objectTargetPosition = targetPosition + mod; if (!object) { moveObject(*player, targetPosition); player->objectMoved(); player->doWork(game.balance.Player_MoveCost); } else if (object->type == WorldObject::ObjectType::FoodObject) { player->eat(); removeFromGrid(object); removeFromList(object); delete object; moveObject(*player, targetPosition); player->objectMoved(); } else if (inRange(objectTargetPosition)) { auto objectObstacle = getObject(objectTargetPosition); if (!object->isPushable()) { } else if (!objectObstacle) { moveObject(*player, targetPosition); player->objectMoved(); moveObject(*object, targetPosition + mod); player->doWork(game.balance.Player_MoveCost + game.balance.Player_PushCost); } /// cant push, see if we can combine else if (object->type == WorldObject::ObjectType::SandObject && objectObstacle->type == WorldObject::ObjectType::SandObject) { // merge the sand object auto sandSource = static_cast<SandObject*>(object); auto sandTarget = static_cast<SandObject*>(objectObstacle); if (sandSource->count + sandTarget->count <= 4) { // can only merge if their total is < 4 sandTarget->count += sandSource->count; // respawn sandSource sandSource->count = 1; removeFromGrid(sandSource); removeFromList(sandSource); moveObject(*player, targetPosition); player->objectMoved(); if (spawnSand()) { spawnObject(sandSource); } else { delete sandSource; } } player->doWork(game.balance.Player_MoveCost + game.balance.Player_PushCost); } else if (object->type == WorldObject::ObjectType::SandObject && objectObstacle->type == WorldObject::ObjectType::WaterObject) { auto sandSource = static_cast<SandObject*>(object); auto waterTarget = static_cast<WaterObject*>(objectObstacle); if (waterTarget->flood) { removeFromGrid(waterTarget); removeFromList(waterTarget); waterTarget->flood = false; waterTarget->floodMeter = 0; outputBlocks.push_back(waterTarget); sandSource->count-=1; if (sandSource->count <= 0) { removeFromGrid(sandSource); removeFromList(sandSource); delete sandSource; } else { moveObject(*sandSource, objectTargetPosition); } moveObject(*player, targetPosition); player->objectMoved(); } player->doWork(game.balance.Player_MoveCost + game.balance.Player_PushCost); } else if (object->type == WorldObject::ObjectType::TreeObject && objectObstacle->type == WorldObject::ObjectType::WaterObject) { auto treeSource = static_cast<TreeObject*>(object); auto waterTarget = static_cast<WaterObject*>(objectObstacle); if (treeSource->grow()) { removeFromGrid(waterTarget); removeFromList(waterTarget); delete waterTarget; moveObject(*treeSource, objectTargetPosition); moveObject(*player, targetPosition); player->objectMoved(); } player->doWork(game.balance.Player_MoveCost + game.balance.Player_PushCost); } else if (object->type == WorldObject::ObjectType::StoneObject && objectObstacle->type == WorldObject::ObjectType::VolcanoObject) { auto volcanoTarget = static_cast<VolcanoObject*>(objectObstacle); volcanoTarget->blocked = true; removeFromGrid(object); removeFromList(object); delete object; moveObject(*player, targetPosition); player->objectMoved(); player->doWork(game.balance.Player_MoveCost + game.balance.Player_PushCost); } } } } } }
void Monster::pushMonsters() { if (!isAlive() || !canPushCreatures()) { return; } auto creatures = getTile()->getCreatures(); if (creatures == nullptr) { return; } bool hasPushableMonsters = false; for (const auto& creature : *creatures) { if (creature == this) { continue; } auto monster = creature->getMonster(); if (monster == nullptr) { continue; } if (!monster->isPushable()) { continue; } hasPushableMonsters = true; break; } if (!hasPushableMonsters) { // optimization to prevent unnecessary vector copy below return; } auto initialCreatures = *creatures; bool killedCreatures = false; for (const auto& creature : initialCreatures) { if (creature == this) { continue; } auto monster = creature->getMonster(); if (monster == nullptr) { continue; } if (!monster->isPushable()) { continue; } Direction direction = monster->getRandomStepDirection(false); if (!monster->stepInDirection(direction)) { monster->setDropLoot(LOOT_DROP_NONE); monster->drainHealth(this, COMBAT_DEATHDAMAGE, -monster->getHealth()); killedCreatures = true; } } if (killedCreatures) { server.game().addMagicEffect(getPosition(), MAGIC_EFFECT_BLOCKHIT); } }