/* * I love Qt */ #include "cell.h" #include "units/unit.h" #include "hotseatgame/gameproperties.h" #include #include #include #include #include #include #include #include #include class EffectsForCell{ public: void OperateOnCell(Cell*){} }; Cell::Cell(QGraphicsItem* parent) : QGraphicsItem(parent) { leftUp_ = left_ = leftDown_ = nullptr; rightUp_ = right_ = rightDown_ = nullptr; clearCell_(); AddedToQuery_ = true; col_ = row_ = 0; hovered_ = false; coor_x_ = coor_y_ = -1; setAcceptHoverEvents(true); } Cell * Cell::getleftUp() { return leftUp_; } void Cell::setleftUp(Cell * t) { leftUp_ = t; } Cell * Cell::getleft() { return left_; } void Cell::setleft(Cell * t) { left_ = t; } Cell * Cell::getleftDown() { return leftDown_; } void Cell::setleftDown(Cell * t) { leftDown_ = t; } Cell * Cell::getrightUp() { return rightUp_; } void Cell::setrightUp(Cell * t) { rightUp_ = t; } Cell * Cell::getright() { return right_; } void Cell::setright(Cell * t) { right_ = t; } Cell * Cell::getrightDown() { return rightDown_; } void Cell::setrightDown(Cell * t) { rightDown_ = t; } std::shared_ptr Cell::getCharacter() { return character_; } void Cell::setCharacter(std::shared_ptr t) { character_ = t; } double Cell::getXCoordinate() { return coor_x_; } void Cell::setXCoordinate(double coordinate) { coor_x_ = coordinate; } double Cell::getYCoordinate() { return coor_y_; } void Cell::setYCoordinate(double coordinate) { coor_y_ = coordinate; } int Cell::getdistance_barrier(){ return distance_barrier_; } void Cell::setdistance_barrier(int distance_barrier){ distance_barrier_ = distance_barrier; } int Cell::getdistance_through(){ return distance_through_; } void Cell::setdistance_through(int distance_through){ distance_through_ = distance_through; } bool Cell::getisMoveAble(){ return isMoveAble_; } void Cell::setisMoveAble(bool isMoveAble){ isMoveAble_ = isMoveAble; } bool Cell::getisMeleeAttackAble(){ return isMeleeAttackAble_; } void Cell::setisMeleeAttackAble(bool isMeleeAttackAble){ isMeleeAttackAble_ = isMeleeAttackAble; } bool Cell::getisRangeAttackAble(){ return isRangeAttackAble_; } void Cell::setisRangeAttackAble(bool isRangeAttackAble){ isRangeAttackAble_ = isRangeAttackAble; } bool Cell::isEmpty() { return character_ == nullptr; } void Cell::recalculateAllEffectsList(){ for(std::vector::iterator it = beginIteratorEffectsList(); it != endIteratorEffectsList();++it){ (*it)->OperateOnCell(this); } } void Cell::add(EffectsForCell* effect){ if(effect == nullptr) throw new int(228); effects_list_.push_back(effect); } void Cell::remove(std::vector::iterator it){ if(beginIteratorEffectsList() <= it && it < endIteratorEffectsList()){ effects_list_.erase(it); } } void Cell::remove(EffectsForCell* effect){ for(std::vector::iterator it = beginIteratorEffectsList(); it != endIteratorEffectsList();++it){ if((*it) == effect){ remove(it); return; } } } std::vector::iterator Cell::beginIteratorEffectsList(){ return effects_list_.begin(); } std::vector::iterator Cell::endIteratorEffectsList(){ return effects_list_.end(); } void Cell::RecalculateTableWithCenterThisPoint() { clearTable_(); std::queue qWithUnMoveable; updateMoveableCells_(qWithUnMoveable); updateUnMovealeCells_(qWithUnMoveable); } std::vector Cell::actualPath(Cell* to) { if (!to || !to->getisMoveAble())return std::vector(); auto ret = std::vector(1, to); while (to != this) { Cell * parent = nullptr; auto f = [&parent](Cell * TestParent, Cell * Now) { if (TestParent && TestParent->getdistance_barrier() + 1 == Now->getdistance_barrier() && TestParent->getisMoveAble()) { parent = TestParent; } }; if(parent == nullptr) throw std::string("Don`t recalculated"); f(to->getleftUp(), to); f(to->getleft(), to); f(to->getleftDown(), to); f(to->getrightUp(), to); f(to->getright(), to); f(to->getrightDown(), to); to = parent; ret.push_back(to); } return ret; } void Cell::clearCell_() { setdistance_barrier(-1); setdistance_through(-1); setisMeleeAttackAble(false); setisMoveAble(false); setisRangeAttackAble(false); } QRectF Cell::boundingRect() const { return QRectF(polygon.boundingRect()); } void Cell::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { polygon.clear(); auto points = getPoints(GameProperties::CELL_MAX_RADIUS, 0); for (auto point : points) { polygon << QPoint(point.first, point.second); } polygon << QPoint(points[0].first, points[0].second); QPen pen = QPen(Qt::green, 2); painter->setPen(pen); painter->setBrush(Qt::green); // We set the brush, which will render the object painter->drawPolyline(polygon); // Draw a triangle on a polygonal model if (hovered_) { painter->setOpacity(0.4); painter->drawPolygon(polygon); } } bool Cell::contains(const QPointF &point) const { return polygon.contains(point.toPoint()); } bool Cell::isHovered() { return hovered_; } void Cell::setHovered(bool hovered) { hovered_ = hovered; } void Cell::hoverEnterEvent(QGraphicsSceneHoverEvent *) { hovered_ = true; update(); } void Cell::hoverLeaveEvent(QGraphicsSceneHoverEvent *) { hovered_ = false; update(); } void Cell::clearTable_() { std::queue q; q.push(this); clearCell_(); setdistance_through(0); this->AddedToQuery_ = false; auto f = [&q](Cell * t, Cell * parent, int delta_col, int delta_row) { if (t && t->AddedToQuery_ == true) { q.push(t); t->col_ = parent->col_ + delta_col; t->row_ = parent->row_ + delta_row; t->setdistance_through( parent->getdistance_through() + 1 ); t->AddedToQuery_ = false; } }; while (!q.empty()) { Cell * Now = q.front(); q.pop(); Now->clearCell_(); f(Now->getleftUp(), Now, -1, 0); f(Now->getleft(), Now, 0, -1); f(Now->getleftDown(), Now, 1, -1); f(Now->getrightUp(), Now, -1, 1); f(Now->getright(), Now, 0, 1); f(Now->getrightDown(), Now, 1, 0); } } void Cell::recalcAttackable_(Cell *, bool){ // if(Now == nullptr)return; // if (!isEmpty() && !Now->isEmpty() && // getCharacter()->canAttackForDistance("Melee", Now->getdistance_barrier()) // ) { // Now->setisMeleeAttackAble(isReached); // } // if (!isEmpty() && !Now->isEmpty() && // getCharacter()->canAttackForDistance("Range", Now->getdistance_barrier()) // ) { // Now->setisRangeAttackAble(true); // } // return; } void Cell::recalcMoveable_(Cell * Now, bool isReached){ if(Now == nullptr || Now->isEmpty() || isEmpty())return; Now->setisMoveAble(isReached); } void Cell::updateMoveableCells_(std::queue & Q) { std::queue q; q.push(this); setdistance_barrier(0); auto f = [&q, &Q](Cell * t, Cell * parent) { if (t && !t->AddedToQuery_) { t->AddedToQuery_ = true; if (t->getCharacter() != NULL) { Q.push(t); return; } q.push(t); t->setdistance_barrier( parent->getdistance_barrier() + 1 ); } }; while (!q.empty()) { Cell * Now = q.front(); q.pop(); recalcMoveable_(Now, true); recalcAttackable_(Now, true); f(Now->getleftUp(), Now); f(Now->getleft(), Now); f(Now->getleftDown(), Now); f(Now->getrightUp(), Now); f(Now->getright(), Now); f(Now->getrightDown(), Now); } } void Cell::updateUnMovealeCells_(std::queue & Q) { auto f = [&Q](Cell * t, Cell * parent) { if (t && !t->AddedToQuery_) { parent->getCharacter(); t->AddedToQuery_ = true; Q.push(t); } }; while (!Q.empty()) { Cell * Now = Q.front(); recalcMoveable_(Now, false); recalcAttackable_(Now, false); Q.pop(); f(Now->getleftUp(), Now); f(Now->getleft(), Now); f(Now->getleftDown(), Now); f(Now->getrightUp(), Now); f(Now->getright(), Now); f(Now->getrightDown(), Now); } } Cell* Cell::getRealShootTarget(Cell* next){ if(next == this){ return next; } int next_col = next->col_; int next_row = next->row_; if(next_col - col_ == next_row - row_){//GoMainDiagonal if(next_col > col_){ return getrightDown()->getright(); } if(next_col < col_){ return getleftUp()->getleft(); } throw std::string("Don`t recalculated"); } if(-2 * (next_col - col_) == (next_row - row_)){//GoSecondaryDiagonal if(next_col < col_){ return getrightUp()->getright(); } if(next_col > col_){ return getleftDown()->getleft(); } throw std::string("Don`t recalculated"); } if(next_col - col_ == -2 * (next_row - row_)){//GoUp if(next_col < col_){ return (getleftUp() != nullptr ? getleftUp()->getrightUp() : getrightUp()->getleftUp()); } if(next_col > col_){ return (getleftDown() != nullptr ? getleftDown()->getrightDown() : getrightDown()->getleftDown()); } throw std::string("Don`t recalculated"); } int row_secondary_diag = row_ - 2 * (next_col - col_); int row_main_diag = row_ + next_col - col_; int twice_row_up_line = 2 * row_ + col_ - next_col; if(next_col > col_){ if(next_row < row_main_diag)return getleft(); if(2 * next_row < twice_row_up_line)return getleftUp(); if(next_row < row_secondary_diag)return getrightUp(); return getright(); } else{ if(next_row < row_secondary_diag)return getleft(); if(2 * next_row < twice_row_up_line)return getleftDown(); if(next_row < row_main_diag)return getrightDown(); return getright(); } } std::vector > Cell::getPoints(double radius, double start_angle) { const double delta_radians = M_PI / 180.0; std::vector > res; std::vector angles = {0, 60, 120, 180, 240, 300}; for(size_t i = 0; i < angles.size(); ++i){ angles[i] += start_angle; res.push_back({std::round(radius * std::sin(angles[i] * delta_radians)), std::round(radius * std::cos(angles[i] * delta_radians))}); } return res; }