File indexing completed on 2024-04-28 04:04:39
0001 /* 0002 This file is part of the game 'KTron' 0003 0004 SPDX-FileCopyrightText: 1998-2000 Matthias Kiefer <matthias.kiefer@gmx.de> 0005 SPDX-FileCopyrightText: 2005 Benjamin C. Meyer <ben at meyerhome dot net> 0006 SPDX-FileCopyrightText: 2008-2009 Stas Verberkt <legolas at legolasweb dot nl> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 0010 */ 0011 0012 #include "player.h" 0013 0014 #include "tron.h" 0015 #include "settings.h" 0016 0017 #include "ksnakeduel_debug.h" 0018 #include <KLocalizedString> 0019 #include <KUser> 0020 0021 Player::Player(PlayField &pf, int playerNr) : QObject() 0022 { 0023 m_playField = &pf; 0024 m_playerNumber = playerNr; 0025 m_computer = false; 0026 0027 // Calling setName() with an empty string will cause the defaults 0028 setName(QString()); 0029 0030 m_score = 0; 0031 m_dir = PlayerDirections::Up; 0032 m_enlarge = 0; 0033 m_blockSwitchDir = false; 0034 0035 reset(); 0036 } 0037 0038 // 0039 // Get / Set 0040 // 0041 0042 int Player::getPlayerNumber() 0043 { 0044 return m_playerNumber; 0045 } 0046 0047 int Player::getX() 0048 { 0049 if (m_snakeParts.isEmpty()) 0050 { 0051 qCDebug(KSNAKEDUEL_LOG) << "Requested coordinate of nonexistent snake"; 0052 return 0; 0053 } 0054 0055 return m_snakeParts.last().getX(); 0056 } 0057 0058 int Player::getY() 0059 { 0060 if (m_snakeParts.isEmpty()) 0061 { 0062 qCDebug(KSNAKEDUEL_LOG) << "Requested coordinate of nonexistent snake"; 0063 return 0; 0064 } 0065 0066 return m_snakeParts.last().getY(); 0067 } 0068 0069 int Player::getScore() 0070 { 0071 return m_score; 0072 } 0073 0074 // 0075 // Player name 0076 // 0077 0078 QString Player::getName() const 0079 { 0080 if (isComputer()) 0081 { 0082 return i18n("KSnakeDuel"); 0083 } 0084 else 0085 { 0086 return m_name; 0087 } 0088 } 0089 0090 void Player::setName(const QString &name) 0091 { 0092 if (name.isEmpty()) 0093 { 0094 // If first player, name it after the user 0095 KUser thisUser = KUser(); 0096 0097 if (m_playerNumber == 0 && thisUser.property(KUser::FullName).isValid()) 0098 { 0099 this->m_name = thisUser.property(KUser::FullName).toString(); 0100 } 0101 else 0102 { 0103 this->m_name = i18n("Player %1", m_playerNumber + 1); 0104 } 0105 } 0106 else 0107 { 0108 this->m_name = name; 0109 } 0110 } 0111 0112 // 0113 // Snake growing 0114 // 0115 0116 void Player::setEnlargement(int enlargement) 0117 { 0118 if (enlargement < 0) 0119 { 0120 return; 0121 } 0122 0123 m_enlarge += enlargement; 0124 } 0125 0126 // 0127 // Directions 0128 // 0129 0130 PlayerDirections::Direction Player::getDirection() 0131 { 0132 return m_dir; 0133 } 0134 0135 void Player::setDirection(PlayerDirections::Direction direction) 0136 { 0137 if (m_blockSwitchDir) 0138 { 0139 return; 0140 } 0141 else if (direction == PlayerDirections::Up && m_dir == PlayerDirections::Down) 0142 { 0143 return; 0144 } 0145 else if (direction == PlayerDirections::Down && m_dir == PlayerDirections::Up) 0146 { 0147 return; 0148 } 0149 else if (direction == PlayerDirections::Left && m_dir == PlayerDirections::Right) 0150 { 0151 return; 0152 } 0153 else if (direction == PlayerDirections::Right && m_dir == PlayerDirections::Left) 0154 { 0155 return; 0156 } 0157 0158 m_dir = direction; 0159 m_blockSwitchDir = true; 0160 } 0161 0162 // 0163 // Live Control 0164 // 0165 0166 bool Player::isAlive() 0167 { 0168 return m_alive; 0169 } 0170 0171 void Player::die() 0172 { 0173 m_alive = false; 0174 } 0175 0176 // 0177 // Score updating 0178 // 0179 0180 void Player::addScore(int increment) 0181 { 0182 if (increment < 0) 0183 { 0184 return; 0185 } 0186 0187 m_score += increment; 0188 } 0189 0190 void Player::resetScore() 0191 { 0192 m_score = 0; 0193 } 0194 0195 // 0196 // Start 0197 // 0198 0199 void Player::setStartPosition() 0200 { 0201 while (!m_snakeParts.isEmpty()) 0202 { 0203 m_snakeParts.dequeue(); 0204 } 0205 0206 int x = (2 - getPlayerNumber()) * m_playField->getWidth() / 3; 0207 int y = m_playField->getHeight() / 2; 0208 0209 SnakePart head(getPlayerNumber()); 0210 head.setPartTop(true); 0211 head.setPartLeft(true); 0212 head.setPartRight(true); 0213 head.setPartType(SnakePartType::Head); 0214 head.generateSVGName(); 0215 0216 SnakePart tail(getPlayerNumber()); 0217 tail.setPartBottom(true); 0218 tail.setPartLeft(true); 0219 tail.setPartRight(true); 0220 if (Settings::gameType() == Settings::EnumGameType::Snake) 0221 { 0222 tail.setPartType(SnakePartType::Tail); 0223 } 0224 else 0225 { 0226 tail.setPartType(SnakePartType::Hole); 0227 } 0228 tail.generateSVGName(); 0229 0230 m_playField->setObjectAt(x, y, head); 0231 m_playField->setObjectAt(x, y + 1, tail); 0232 0233 m_snakeParts.enqueue(tail); 0234 m_snakeParts.enqueue(head); 0235 0236 // Make the computer player start some random direction 0237 if (isComputer()) 0238 { 0239 switch ((int)(rand() % 3)) 0240 { 0241 default: 0242 case 0: 0243 m_dir = PlayerDirections::Up; 0244 break; 0245 case 1: 0246 m_dir = PlayerDirections::Left; 0247 break; 0248 case 2: 0249 m_dir = PlayerDirections::Right; 0250 break; 0251 } 0252 0253 m_blockSwitchDir = true; 0254 } 0255 else 0256 { 0257 m_dir = PlayerDirections::Up; 0258 } 0259 } 0260 0261 // 0262 // Movement 0263 // 0264 0265 void Player::movePlayer() 0266 { 0267 int oldX = m_snakeParts.last().getX(); 0268 int oldY = m_snakeParts.last().getY(); 0269 SnakePart newHead(m_playerNumber); 0270 0271 int newX = oldX; 0272 int newY = oldY; 0273 0274 newHead.setPartType(SnakePartType::Head); 0275 0276 switch (m_dir) 0277 { 0278 case PlayerDirections::Up: 0279 newY--; 0280 newHead.setPartTop(true); 0281 newHead.setPartLeft(true); 0282 newHead.setPartRight(true); 0283 break; 0284 case PlayerDirections::Down: 0285 newY++; 0286 newHead.setPartBottom(true); 0287 newHead.setPartLeft(true); 0288 newHead.setPartRight(true); 0289 break; 0290 case PlayerDirections::Left: 0291 newX--; 0292 newHead.setPartTop(true); 0293 newHead.setPartBottom(true); 0294 newHead.setPartLeft(true); 0295 break; 0296 case PlayerDirections::Right: 0297 newX++; 0298 newHead.setPartTop(true); 0299 newHead.setPartBottom(true); 0300 newHead.setPartRight(true); 0301 break; 0302 default: 0303 break; 0304 } 0305 0306 if (crashed(newX, newY)) 0307 { 0308 //qCDebug(KSNAKEDUEL_LOG) << "Crashed at: (" << newX << ", " << newY << ")"; 0309 m_alive = false; 0310 } 0311 0312 if (m_alive) 0313 { 0314 switch (m_dir) 0315 { 0316 // unset drawing flags in the moving direction 0317 case PlayerDirections::Up: 0318 m_snakeParts.last().setPartTop(false); 0319 break; 0320 case PlayerDirections::Down: 0321 m_snakeParts.last().setPartBottom(false); 0322 break; 0323 case PlayerDirections::Right: 0324 m_snakeParts.last().setPartRight(false); 0325 break; 0326 case PlayerDirections::Left: 0327 m_snakeParts.last().setPartLeft(false); 0328 break; 0329 default: 0330 break; 0331 } 0332 m_snakeParts.last().setPartType(SnakePartType::Body); 0333 m_snakeParts.last().generateSVGName(); 0334 m_playField->setObjectAt(m_snakeParts.last().getX(), m_snakeParts.last().getY(), m_snakeParts.last()); 0335 0336 if (m_playField->getObjectAt(newX, newY)->getObjectType() == ObjectType::Item) 0337 { 0338 //qCDebug(KSNAKEDUEL_LOG) << "Boom!"; 0339 Q_EMIT fetchedItem(m_playerNumber, newX, newY); 0340 } 0341 0342 newHead.generateSVGName(); 0343 m_playField->setObjectAt(newX, newY, newHead); 0344 m_snakeParts.enqueue(newHead); 0345 } 0346 0347 if (m_alive && m_enlarge == 0 && Settings::gameType() == Settings::EnumGameType::Snake) 0348 { 0349 SnakePart oldTail = m_snakeParts.dequeue(); 0350 0351 if (!oldTail.getPartTop()) 0352 { 0353 m_snakeParts.head().setPartBottom(true); 0354 } 0355 else if (!oldTail.getPartBottom()) 0356 { 0357 m_snakeParts.head().setPartTop(true); 0358 } 0359 else if (!oldTail.getPartLeft()) 0360 { 0361 m_snakeParts.head().setPartRight(true); 0362 } 0363 else if (!oldTail.getPartRight()) 0364 { 0365 m_snakeParts.head().setPartLeft(true); 0366 } 0367 0368 m_snakeParts.head().setPartType(SnakePartType::Tail); 0369 m_snakeParts.head().generateSVGName(); 0370 m_playField->setObjectAt(m_snakeParts.head().getX(), m_snakeParts.head().getY(), m_snakeParts.head()); 0371 0372 Object emptyObject = Object(); 0373 m_playField->setObjectAt(oldTail.getX(), oldTail.getY(), emptyObject); 0374 } 0375 else if (m_enlarge > 0) 0376 { 0377 m_enlarge--; 0378 } 0379 0380 m_blockSwitchDir = false; 0381 } 0382 0383 // 0384 // Crash check 0385 // 0386 0387 bool Player::crashed(int x, int y) 0388 { 0389 if (x < 0 || y < 0 || x >= m_playField->getWidth() || y >= m_playField->getHeight()) 0390 { 0391 return true; 0392 } 0393 else 0394 { 0395 ObjectType::Type objType = m_playField->getObjectAt(x, y)->getObjectType(); 0396 return (objType != ObjectType::Item && objType != ObjectType::Object); 0397 } 0398 } 0399 0400 // 0401 // Reset 0402 // 0403 0404 void Player::reset() 0405 { 0406 m_alive = true; 0407 m_accelerated = false; 0408 m_enlarge = 0; 0409 m_keyPressed = m_computer; 0410 m_blockSwitchDir = false; 0411 } 0412 0413 // 0414 // Computer powered 0415 // 0416 0417 bool Player::isComputer() const 0418 { 0419 return m_computer; 0420 } 0421 0422 void Player::setComputer(bool isComputer) 0423 { 0424 m_computer = isComputer; 0425 m_keyPressed = m_computer; 0426 } 0427 0428 // 0429 // Acceleration 0430 // 0431 0432 bool Player::isAccelerated() 0433 { 0434 return m_accelerated; 0435 } 0436 0437 void Player::setAccelerated(bool value) 0438 { 0439 m_accelerated = value; 0440 } 0441 0442 0443 // 0444 // Key pressed 0445 // 0446 0447 bool Player::hasKeyPressed() 0448 { 0449 return m_keyPressed; 0450 } 0451 0452 void Player::setKeyPressed(bool value) 0453 { 0454 m_keyPressed = value; 0455 } 0456 0457 #include "moc_player.cpp"