File indexing completed on 2024-09-08 03:45:24
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"