File indexing completed on 2024-05-05 05:40:25
0001 /*************************************************************************** 0002 * Copyright (C) 2015 by Renaud Guezennec * 0003 * https://rolisteam.org/contact * 0004 * * 0005 * rolisteam is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 #include <QBuffer> 0021 #include <QColor> 0022 #include <QDebug> 0023 #include <QFileInfo> 0024 #include <QIcon> 0025 #include <QJsonArray> 0026 #include <QJsonObject> 0027 #include <QJsonValue> 0028 #include <QNetworkAccessManager> 0029 #include <QNetworkReply> 0030 #include <QPixmap> 0031 #include <QUuid> 0032 0033 #include "charactersheet/rolisteamimageprovider.h" 0034 0035 #include "worker/iohelper.h" 0036 0037 #include "data/character.h" 0038 #ifndef UNIT_TEST 0039 #include "charactersheet.h" 0040 #endif 0041 #include "data/player.h" 0042 0043 // Begin character field 0044 CharacterField::CharacterField() {} 0045 0046 CharacterField::~CharacterField() {} 0047 0048 CharacterShape::CharacterShape() {} 0049 0050 QString CharacterShape::name() const 0051 { 0052 return m_name; 0053 } 0054 0055 void CharacterShape::setName(const QString& name) 0056 { 0057 m_name= name; 0058 } 0059 0060 const QImage& CharacterShape::image() const 0061 { 0062 return m_image; 0063 } 0064 0065 void CharacterShape::setImage(const QImage& image) 0066 { 0067 m_image= image; 0068 } 0069 0070 const QMovie& CharacterShape::movie() const 0071 { 0072 return m_movie; 0073 } 0074 0075 void CharacterShape::setMovie(const QMovie& movie) 0076 { 0077 m_movie.setFileName(movie.fileName()); 0078 } 0079 0080 QString CharacterShape::uri() const 0081 { 0082 return m_uri; 0083 } 0084 0085 void CharacterShape::setUri(const QString& uri) 0086 { 0087 if(m_uri == uri) 0088 return; 0089 0090 m_uri= uri; 0091 updateImage(); 0092 } 0093 0094 QVariant CharacterShape::getData(int col, int role) 0095 { 0096 if(Qt::DisplayRole == role || Qt::EditRole == role) 0097 { 0098 if(col == 0) 0099 { 0100 return name(); 0101 } 0102 else if(col == 1) 0103 { 0104 return uri(); 0105 } 0106 } 0107 else if(Qt::DecorationRole == role && col == 0 && !m_image.isNull()) 0108 { 0109 return QPixmap::fromImage(m_image).scaled(m_size, m_size, Qt::KeepAspectRatio); 0110 } 0111 return QVariant(); 0112 } 0113 0114 bool CharacterShape::setData(int col, QVariant value, int role) 0115 { 0116 bool set= false; 0117 if(Qt::DisplayRole == role || Qt::EditRole == role) 0118 { 0119 if(col == 0) 0120 { 0121 setName(value.toString()); 0122 set= true; 0123 } 0124 else if(col == 1) 0125 { 0126 setUri(value.toString()); 0127 set= true; 0128 } 0129 } 0130 return set; 0131 } 0132 0133 void CharacterShape::updateImage() 0134 { 0135 m_image= QImage(m_uri); 0136 } 0137 0138 void CharacterShape::setSize(int size) 0139 { 0140 if(size == m_size) 0141 return; 0142 m_size= size; 0143 } 0144 0145 /////////////////////////////////// 0146 /// 0147 /// Start CharacterAction 0148 /// 0149 /////////////////////////////////// 0150 0151 CharacterAction::CharacterAction() {} 0152 0153 QString CharacterAction::name() const 0154 { 0155 return m_name; 0156 } 0157 0158 void CharacterAction::setName(const QString& name) 0159 { 0160 m_name= name; 0161 } 0162 0163 QString CharacterAction::command() const 0164 { 0165 return m_command; 0166 } 0167 0168 void CharacterAction::setCommand(const QString& command) 0169 { 0170 m_command= command; 0171 } 0172 0173 QVariant CharacterAction::getData(int col, int role) 0174 { 0175 if(Qt::DisplayRole == role || Qt::EditRole == role) 0176 { 0177 if(col == 0) 0178 { 0179 return name(); 0180 } 0181 else if(col == 1) 0182 { 0183 return command(); 0184 } 0185 } 0186 return QVariant(); 0187 } 0188 0189 bool CharacterAction::setData(int col, QVariant value, int role) 0190 { 0191 bool set= false; 0192 if(Qt::DisplayRole == role || Qt::EditRole == role) 0193 { 0194 if(col == 0) 0195 { 0196 setName(value.toString()); 0197 set= true; 0198 } 0199 else if(col == 1) 0200 { 0201 setCommand(value.toString()); 0202 set= true; 0203 } 0204 } 0205 return set; 0206 } 0207 0208 CharacterProperty::CharacterProperty() {} 0209 0210 QString CharacterProperty::name() const 0211 { 0212 return m_name; 0213 } 0214 0215 void CharacterProperty::setName(const QString& name) 0216 { 0217 m_name= name; 0218 } 0219 0220 QString CharacterProperty::value() const 0221 { 0222 return m_value; 0223 } 0224 0225 void CharacterProperty::setValue(const QString& value) 0226 { 0227 m_value= value; 0228 } 0229 0230 QVariant CharacterProperty::getData(int col, int role) 0231 { 0232 if(Qt::DisplayRole == role || Qt::EditRole == role) 0233 { 0234 if(col == 0) 0235 { 0236 return name(); 0237 } 0238 else if(col == 1) 0239 { 0240 return value(); 0241 } 0242 } 0243 return QVariant(); 0244 } 0245 0246 bool CharacterProperty::setData(int col, QVariant value, int role) 0247 { 0248 bool set= false; 0249 if(Qt::DisplayRole == role || Qt::EditRole == role) 0250 { 0251 if(col == 0) 0252 { 0253 setName(value.toString()); 0254 set= true; 0255 } 0256 else if(col == 1) 0257 { 0258 setValue(value.toString()); 0259 set= true; 0260 } 0261 } 0262 return set; 0263 } 0264 0265 // end character field 0266 0267 QList<CharacterState*>* Character::m_stateList= nullptr; 0268 0269 Character::Character(QObject* parent) : Person(parent), m_sheet(nullptr) {} 0270 0271 Character::Character(const QString& name, const QColor& color, bool npc, int number) 0272 : Person(name, color), m_isNpc(npc), m_number(number), m_sheet(nullptr) 0273 { 0274 } 0275 0276 Character::Character(const QString& uuid, const QString& name, const QColor& color, bool npc, int number) 0277 : Person(name, color, uuid), m_isNpc(npc), m_number(number), m_sheet(nullptr) 0278 { 0279 } 0280 0281 /*Character::Character(NetworkMessageReader& data) : Person(), m_sheet(nullptr) 0282 { 0283 read(data); 0284 }*/ 0285 0286 Character::~Character() {} 0287 0288 QList<CharacterShape*> Character::shapeList() const 0289 { 0290 return m_shapeList; 0291 } 0292 0293 QList<CharacterAction*> Character::actionList() const 0294 { 0295 return m_actionList; 0296 } 0297 0298 QList<CharacterProperty*> Character::propertiesList() const 0299 { 0300 return m_propertyList; 0301 } 0302 0303 void Character::defineActionList(const QList<CharacterAction*>& actions) 0304 { 0305 m_actionList.clear(); 0306 m_actionList << actions; 0307 } 0308 0309 void Character::defineShapeList(const QList<CharacterShape*>& shape) 0310 { 0311 m_shapeList.clear(); 0312 m_shapeList << shape; 0313 } 0314 void Character::definePropertiesList(const QList<CharacterProperty*>& props) 0315 { 0316 m_propertyList.clear(); 0317 m_propertyList << props; 0318 } 0319 0320 RolisteamImageProvider* Character::getImageProvider() const 0321 { 0322 return m_imageProvider; 0323 } 0324 0325 void Character::setImageProvider(RolisteamImageProvider* imageProvider) 0326 { 0327 m_imageProvider= imageProvider; 0328 } 0329 0330 qreal Character::getDistancePerTurn() const 0331 { 0332 return m_distancePerTurn; 0333 } 0334 0335 void Character::setDistancePerTurn(const qreal& distancePerTurn) 0336 { 0337 if(qFuzzyCompare(m_distancePerTurn, distancePerTurn)) 0338 return; 0339 m_distancePerTurn= distancePerTurn; 0340 emit distancePerTurnChanged(); 0341 } 0342 0343 int Character::getInitiativeScore() const 0344 { 0345 return m_initiativeScore; 0346 } 0347 0348 void Character::setInitiativeScore(int intiativeScore) 0349 { 0350 if(m_initiativeScore == intiativeScore) 0351 return; 0352 m_initiativeScore= intiativeScore; 0353 setHasInitiative(true); 0354 emit initiativeChanged(); 0355 } 0356 0357 int Character::getHealthPointsCurrent() const 0358 { 0359 return m_healthPointsCurrent; 0360 } 0361 0362 void Character::setHealthPointsCurrent(int hpCurrent) 0363 { 0364 if(hpCurrent == m_healthPointsCurrent) 0365 return; 0366 m_healthPointsCurrent= qBound(m_healthPointsMin, hpCurrent, m_healthPointsMax); 0367 emit currentHealthPointsChanged(); 0368 } 0369 0370 int Character::getHealthPointsMin() const 0371 { 0372 return m_healthPointsMin; 0373 } 0374 0375 void Character::setHealthPointsMin(int hpMin) 0376 { 0377 if(hpMin == m_healthPointsMin) 0378 return; 0379 m_healthPointsMin= hpMin; 0380 emit minHPChanged(); 0381 } 0382 0383 int Character::getHealthPointsMax() const 0384 { 0385 return m_healthPointsMax; 0386 } 0387 0388 void Character::setHealthPointsMax(int hpMax) 0389 { 0390 if(hpMax == m_healthPointsMax) 0391 return; 0392 m_healthPointsMax= hpMax; 0393 emit maxHPChanged(); 0394 } 0395 0396 QString Character::getParentId() const 0397 { 0398 if(nullptr != m_parentPerson) 0399 { 0400 return m_parentPerson->uuid(); 0401 } 0402 return QString(); 0403 } 0404 0405 QHash<QString, QString> Character::getVariableDictionnary() 0406 { 0407 QHash<QString, QString> variables; 0408 if(nullptr != m_sheet) 0409 { 0410 #ifndef UNIT_TEST 0411 variables= m_sheet->getVariableDictionnary(); 0412 #endif 0413 } 0414 else if(!m_propertyList.isEmpty()) 0415 { 0416 for(auto& property : m_propertyList) 0417 { 0418 if(property != nullptr) 0419 variables.insert(property->name(), property->value()); 0420 } 0421 } 0422 return variables; 0423 } 0424 0425 CharacterSheet* Character::getSheet() const 0426 { 0427 return m_sheet; 0428 } 0429 0430 void Character::setSheet(CharacterSheet* sheet) 0431 { 0432 m_sheet= sheet; 0433 } 0434 void Character::setListOfCharacterState(QList<CharacterState*>* list) 0435 { 0436 m_stateList= list; 0437 } 0438 int Character::indexOfState(CharacterState* state) 0439 { 0440 if(nullptr != m_stateList) 0441 { 0442 return m_stateList->indexOf(state); 0443 } 0444 else 0445 { 0446 return -1; 0447 } 0448 } 0449 0450 void Character::addShape(const QString& name, const QString& path) 0451 { 0452 auto shape= new CharacterShape(); 0453 0454 if(path.startsWith(QStringLiteral("image://rcs/"))) 0455 { 0456 #ifdef QT_QUICK_LIB 0457 auto key= path; 0458 key.replace(QStringLiteral("image://rcs/"), ""); 0459 QSize size; 0460 QSize resquestedSize; 0461 auto img= m_imageProvider->requestPixmap(key, &size, resquestedSize); 0462 shape->setImage(img.toImage()); 0463 #endif 0464 } 0465 else if(path.startsWith("http")) 0466 { 0467 #ifdef HAVE_QT_NETWORK 0468 QNetworkAccessManager* manager= new QNetworkAccessManager(this); 0469 connect(manager, &QNetworkAccessManager::finished, this, [shape, manager](QNetworkReply* reply) { 0470 QByteArray data= reply->readAll(); 0471 QPixmap map; 0472 bool ok= map.loadFromData(data); 0473 if(ok) 0474 shape->setImage(map.toImage()); 0475 if(manager != nullptr) 0476 delete manager; 0477 }); 0478 0479 manager->get(QNetworkRequest(QUrl(path))); 0480 #endif 0481 } 0482 shape->setName(name); 0483 shape->setUri(path); 0484 m_shapeList.append(shape); 0485 } 0486 0487 CharacterState* Character::getStateFromLabel(QString label) 0488 { 0489 for(auto& state : *m_stateList) 0490 { 0491 if(state->label() == label) 0492 { 0493 return state; 0494 } 0495 } 0496 return nullptr; 0497 } 0498 0499 CharacterState* Character::getStateFromIndex(int i) 0500 { 0501 if(nullptr == m_stateList) 0502 return nullptr; 0503 0504 if(m_stateList->empty()) 0505 return nullptr; 0506 if(m_stateList->size() > i) 0507 { 0508 return m_stateList->at(i); 0509 } 0510 return nullptr; 0511 } 0512 0513 /*QString Character::read(NetworkMessageReader& msg) 0514 { 0515 if(!msg.isValid()) 0516 return {}; 0517 QString parentId= msg.string8(); 0518 m_uuid= msg.string8(); 0519 setName(msg.string16()); 0520 setStateId(msg.string16()); 0521 setNpc(static_cast<bool>(msg.uint8())); 0522 setNumber(msg.int32()); 0523 setColor(QColor(msg.rgb())); 0524 setHealthPointsCurrent(msg.int32()); 0525 setHealthPointsMin(msg.int32()); 0526 setHealthPointsMax(msg.int32()); 0527 setInitiativeScore(msg.int32()); 0528 m_initiativeRoll.setCommand(msg.string32()); 0529 setDistancePerTurn(msg.real()); 0530 m_hasInitScore= static_cast<bool>(msg.uint8()); 0531 0532 bool hasAvatar= static_cast<bool>(msg.uint8()); 0533 0534 if(hasAvatar) 0535 { 0536 auto avatar= QImage::fromData(msg.byteArray32()); 0537 setAvatar(avatar); 0538 } 0539 0540 return parentId; 0541 }*/ 0542 0543 Player* Character::getParentPlayer() const 0544 { 0545 return dynamic_cast<Player*>(m_parentPerson); 0546 } 0547 0548 int Character::number() const 0549 { 0550 return m_number; 0551 } 0552 0553 void Character::setNumber(int n) 0554 { 0555 m_number= n; 0556 } 0557 QColor Character::getLifeColor() const 0558 { 0559 return m_lifeColor; 0560 } 0561 void Character::setLifeColor(QColor color) 0562 { 0563 if(m_lifeColor == color) 0564 return; 0565 0566 m_lifeColor= color; 0567 emit lifeColorChanged(); 0568 } 0569 0570 void Character::setInitCommand(const QString& init) 0571 { 0572 if(m_initiativeRoll.command() == init) 0573 return; 0574 0575 m_initiativeRoll.setCommand(init); 0576 emit initCommandChanged(); 0577 } 0578 QString Character::initCommand() const 0579 { 0580 return m_initiativeRoll.command(); 0581 } 0582 0583 bool Character::isNpc() const 0584 { 0585 return m_isNpc; 0586 } 0587 void Character::setStateId(const QString& stateId) 0588 { 0589 if(stateId == m_stateId) 0590 return; 0591 m_stateId= stateId; 0592 emit stateIdChanged(m_stateId); 0593 } 0594 0595 QString Character::currentStateLabel() const 0596 { 0597 if(!m_stateList) 0598 return {}; 0599 auto it= std::find_if(m_stateList->begin(), m_stateList->end(), [this](const CharacterState* state) { 0600 if(nullptr == state) 0601 return false; 0602 return state->id() == m_stateId; 0603 }); 0604 0605 if(it == m_stateList->end()) 0606 return {}; 0607 return (*it)->label(); 0608 } 0609 0610 QImage Character::currentStateImage() const 0611 { 0612 if(!m_stateList) 0613 return {}; 0614 0615 auto it= std::find_if(m_stateList->begin(), m_stateList->end(), [this](const CharacterState* state) { 0616 if(nullptr == state) 0617 return false; 0618 return state->id() == m_stateId; 0619 }); 0620 if(it == m_stateList->end()) 0621 return {}; 0622 return QImage((*it)->imagePath()); 0623 } 0624 0625 bool Character::hasInitScore() const 0626 { 0627 return m_hasInitScore; 0628 } 0629 0630 void Character::setHasInitiative(bool b) 0631 { 0632 if(m_hasInitScore == b) 0633 return; 0634 m_hasInitScore= b; 0635 emit hasInitScoreChanged(); 0636 } 0637 0638 QString Character::stateId() const 0639 { 0640 return m_stateId; 0641 } 0642 /*void Character::writeData(QDataStream& out) const 0643 { 0644 out << m_uuid; 0645 out << m_name; 0646 out << m_stateId; 0647 out << m_isNpc; 0648 out << m_number; 0649 out << m_color; 0650 out << m_avatar; 0651 } 0652 void Character::readData(QDataStream& in) 0653 { 0654 in >> m_uuid; 0655 in >> m_name; 0656 in >> m_stateId; 0657 in >> m_isNpc; 0658 in >> m_number; 0659 in >> m_color; 0660 in >> m_avatar; 0661 }*/ 0662 0663 QList<CharacterState*>* Character::getCharacterStateList() 0664 { 0665 return m_stateList; 0666 } 0667 void Character::setNpc(bool b) 0668 { 0669 if(m_isNpc == b) 0670 return; 0671 0672 m_isNpc= b; 0673 emit npcChanged(); 0674 } 0675 /*void Character::write(QDataStream& out, bool tag, bool) const 0676 { 0677 if(tag) 0678 { 0679 out << QStringLiteral("Character"); 0680 } 0681 out << m_isNpc; 0682 out << m_number; 0683 out << m_name; 0684 out << m_uuid; 0685 out << m_color; 0686 if(nullptr != m_parentPerson) 0687 out << m_parentPerson->uuid(); 0688 else 0689 out << QString(); 0690 0691 out << static_cast<int>(m_checkState); 0692 0693 QByteArray array; 0694 QBuffer buffer(&array); 0695 buffer.open(QIODevice::WriteOnly); 0696 m_avatar.save(&buffer, "PNG"); 0697 out << array; 0698 } 0699 void Character::read(QDataStream& in) 0700 { 0701 in >> m_isNpc; 0702 in >> m_number; 0703 in >> m_name; 0704 in >> m_uuid; 0705 in >> m_color; 0706 QString parentId; 0707 in >> parentId; 0708 int checkState; 0709 in >> checkState; 0710 m_checkState= static_cast<Qt::CheckState>(checkState); 0711 QByteArray array; 0712 in >> array; 0713 m_avatar= QImage::fromData(array); 0714 }*/ 0715 0716 void Character::setCurrentShape(int index) 0717 { 0718 if(index < 0) 0719 { 0720 setCurrentShape(nullptr); 0721 return; 0722 } 0723 0724 if(qBound(0, index, m_shapeList.size()) != index) 0725 return; 0726 0727 auto shape= m_shapeList[index]; 0728 setCurrentShape(shape); 0729 } 0730 0731 void Character::setCurrentShape(CharacterShape* shape) 0732 { 0733 if(shape == m_currentShape) 0734 return; 0735 m_currentShape= shape; 0736 emit avatarChanged(); 0737 } 0738 0739 void Character::addShape(CharacterShape* shape) 0740 { 0741 m_shapeList.append(shape); 0742 // TODO emit signal ? 0743 } 0744 0745 void Character::addAction(CharacterAction* action) 0746 { 0747 m_actionList.append(action); 0748 // TODO emit signal ? 0749 } 0750 0751 void Character::addProperty(CharacterProperty* property) 0752 { 0753 m_propertyList.append(property); 0754 // TODO emit signal ? 0755 } 0756 0757 QByteArray Character::avatar() const 0758 { 0759 if(nullptr == m_currentShape) 0760 return Person::avatar(); 0761 // else 0762 // return IOHelper::imageToData(m_currentShape->image()); 0763 // TODO change API of shapes 0764 return {}; 0765 } 0766 0767 CharacterShape* Character::currentShape() const 0768 { 0769 return m_currentShape; 0770 }