File indexing completed on 2024-04-28 07:52:39

0001 /*
0002     SPDX-FileCopyrightText: 2007 Paolo Capriotti <p.capriotti@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "playerentity.h"
0008 
0009 #include <KLocalizedString>
0010 
0011 #include "seaview.h"
0012 #include "shot.h"
0013 #include "coord.h"
0014 #include "chatwidget.h"
0015 
0016 PlayerEntity::PlayerEntity(Sea::Player player, Sea* sea, SeaView* view, ChatWidget* chat)
0017 : UIEntity(player, sea, view)
0018 , m_chat(chat)
0019 {
0020     m_seaview->setStatus(Sea::PLACING_SHIPS);
0021 }
0022 
0023 Ship* PlayerEntity::nextShip()
0024 {
0025     if (m_ships.empty()) {
0026         return nullptr;
0027     }
0028     else {
0029         return m_ships.first();
0030     }
0031 }
0032 
0033 Ship* PlayerEntity::canAddShip(const Coord& c)
0034 {
0035     Ship* ship = nextShip();
0036     if (ship) {
0037         ship->setPosition(c);
0038         if (m_sea->canAddShip(m_player, c, ship->size(), ship->direction())) {
0039             // check if it is near any other ship
0040             // in KBS3 mode
0041             if (m_level == COMPAT_KBS3) {
0042                 for (unsigned int i = 0; i < ship->size(); i++) {
0043                     if (m_sea->isNearShip(m_player, c + ship->increment() * i)) {
0044                         return nullptr;
0045                     }
0046                 }
0047             }
0048             return ship;
0049         }
0050     }
0051     return nullptr;
0052 }
0053 
0054 
0055 void PlayerEntity::action(Sea::Player player, const Coord& c)
0056 {
0057     Sea::Player opponent = Sea::opponent(m_player);
0058     switch ( m_sea->status() )
0059     {
0060         case Sea::PLACING_SHIPS: 
0061             if (!m_ships.empty()) {
0062                 if (player == m_player) {
0063                     // placing ships
0064                     // First check if the ship can be placed anywhere
0065                     Ship* ship = canAddShip(c);
0066                     if (ship) {
0067                         // remove ship from the list
0068                         m_ships.removeFirst();
0069 
0070                         // add ship to the sea
0071                         m_sea->add(m_player, ship);
0072                         m_seaview->add(m_player, ship);
0073                         if (!m_ships.empty()) {
0074                             ship=m_ships.first();
0075                             // when multiple ships and an space between them are enabled,
0076                             // it is possible to reach impossible combinations
0077                             if ( !m_sea->canAddShipOfSize(m_player, ship->size()) ) {
0078                                 Q_EMIT restartPlacingShips(m_player);
0079                             }
0080                         }
0081                         else {
0082                             Q_EMIT shipsPlaced();
0083                         }
0084                     }
0085                 }
0086             }
0087             break;
0088         case Sea::PLAYING:
0089             if (player == opponent && m_sea->canHit(m_player, c)) {
0090                 Q_EMIT shoot(m_player, c);
0091             }
0092             break;
0093         default:
0094             // SHOULD NEVER HAPPEN
0095             break;
0096     }
0097 }
0098 
0099 void PlayerEntity::startPlacing()
0100 {
0101     UIEntity::startPlacing();
0102     m_battleShipsConfiguration = m_sea->battleShipsConfiguration();
0103 
0104     Coord origin(0, 0);
0105 
0106     m_sea->clear(m_player);
0107     qDeleteAll(m_ships);
0108     m_ships.clear();
0109     for (unsigned int len=1; len <= m_battleShipsConfiguration->longestShip(); len++)
0110     {
0111         for (unsigned int i=0; i<m_battleShipsConfiguration->numberOfShipsOfSize(len); i++)
0112         {
0113             m_ships.append(new Ship(len, Ship::LEFT_TO_RIGHT, origin));
0114         }
0115     }
0116     m_seaview->setDelegate(this);
0117     m_seaview->setStatus(Sea::PLACING_SHIPS);
0118 }
0119 
0120 
0121 void PlayerEntity::start()
0122 {
0123     UIEntity::start();
0124     Q_EMIT ready(m_player);
0125 }
0126 
0127 void PlayerEntity::startPlaying()
0128 {
0129     UIEntity::startPlaying();
0130     m_seaview->setStatus(Sea::PLAYING);
0131 }
0132 
0133 void PlayerEntity::hit(Shot* shot)
0134 {
0135     if (shot->player() != m_player && m_sea->canHit(shot->player(), shot->pos())) {
0136         HitInfo info = m_sea->hit(shot->pos());
0137         shot->execute(info);
0138     }
0139     else {
0140         shot->execute(HitInfo::INVALID);
0141     }
0142 }
0143 
0144 void PlayerEntity::notify(Sea::Player player, const Coord& c, const HitInfo& info)
0145 {
0146     UIEntity::notify(player, c, info);
0147 }
0148 
0149 void PlayerEntity::changeDirection(Sea::Player player)
0150 {
0151     if (player == m_player) {
0152         Ship* next = nextShip();
0153         if (next) {
0154             next->changeDirection();
0155             m_seaview->cancelPreview();
0156         }
0157     }
0158 }
0159 
0160 bool PlayerEntity::canAddShip(Sea::Player player, const Coord& c)
0161 {
0162     if (m_ships.isEmpty() || player != m_player) {
0163         return false;
0164     }
0165 
0166     Ship * next = m_ships.at(0);
0167 
0168     if (m_sea->canAddShip(player, c, next->size(), next->direction())) {
0169         return true;
0170     }
0171 
0172     return false;
0173 }
0174 
0175 void PlayerEntity::registerHit(Sea::Player player, const Coord&)
0176 {
0177     if (player == m_player) {
0178         m_stats.addHit();
0179     }
0180 }
0181 
0182 void PlayerEntity::registerMiss(Sea::Player player, const Coord&)
0183 {
0184     if (player == m_player) {
0185         m_stats.addMiss();
0186     }
0187 }
0188 
0189 void PlayerEntity::notifyChat(const Entity* entity, const QString& text)
0190 {
0191     if (entity != this) {
0192         qCDebug(KNAVALBATTLE_LOG) << "received chat from" << entity->nick() << ":" << text;
0193         m_chat->display(entity->nick(), text);
0194     }
0195 }
0196 
0197 void PlayerEntity::notifyNick(Sea::Player, const QString& nickname)
0198 {
0199     m_chat->display(i18n("Your opponent is now known as %1", nickname));
0200 }
0201 
0202 void PlayerEntity::notifyAbort()
0203 {
0204     m_chat->display(i18n("Your opponent disconnected from the game"));
0205 }
0206 
0207 void PlayerEntity::setNick(const QString& nick)
0208 {
0209     UIEntity::setNick(nick);
0210     m_chat->setNick(nick);
0211 }
0212 
0213 void PlayerEntity::notifyRestartPlacing(Sea::Player player)
0214 {
0215     UIEntity::notifyRestartPlacing(player);
0216     m_seaview->clear();
0217     m_sea->clear(player);
0218     startPlacing();
0219 }
0220 
0221 #include "moc_playerentity.cpp"