File indexing completed on 2024-04-14 04:00:20

0001 /***************************************************************************
0002                                cmaproom.cpp
0003                              -------------------
0004     begin                : Sat Mar 10 2001
0005     copyright            : (C) 2001 by Kmud Developer Team
0006     email                : kmud-devel@kmud.de
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 #include "cmaproom.h"
0019 
0020 #include <math.h>
0021 
0022 #include <qfontmetrics.h>
0023 #include <qregion.h>
0024 #include <qsize.h>
0025 #include <QDebug>
0026 
0027 #include "cmapmanager.h"
0028 #include "cmappath.h"
0029 #include "cmaptext.h"
0030 #include "cmaplevel.h"
0031 #include "cmapelementutil.h"
0032 #include "cmapview.h"
0033 
0034 
0035 CMapRoom::CMapRoom(CMapManager *manager,QRect rect,CMapLevel *level) : CMapElement(manager,rect,level)
0036 {
0037   color = QColor(192,192,192);
0038   useDefaultCol = true;
0039   login = false;
0040   label = "";
0041   labelPosition = HIDE;
0042   description = "";
0043   current = false;
0044   getZone()->m_room_id_count=getZone()->m_room_id_count+1;
0045   m_ID = getZone()->m_room_id_count;
0046 
0047   level->getRoomList()->append(this);
0048 
0049   textRemove();
0050 }
0051 
0052 CMapRoom::~CMapRoom()
0053 {
0054   CMapLevel *l = getLevel();
0055   CMapManager *manager = getManager();
0056 
0057   CMapRoom *swapRoom = manager->findFirstRoom(this);
0058   if (l->getRoomList()->count() > 1) {
0059     CMapRoom *firstRoom = l->getRoomList()->first();
0060     CMapRoom *lastRoom = l->getRoomList()->last();
0061     swapRoom = (firstRoom == this) ? lastRoom : firstRoom;
0062   }
0063 
0064   if (current)
0065     manager->setCurrentRoom(swapRoom);
0066 
0067   if (login)
0068     manager->setLoginRoom(swapRoom);
0069 
0070   // Delete the paths for the room
0071   // First make a copy, as deleting rooms alters this list
0072   QList<CMapPath *> paths = pathList;
0073   foreach (CMapPath *path, paths) {
0074     path->setOpsitePath(nullptr);  // prevents a crash
0075     delete path;
0076   }
0077 
0078   // Same for paths connecting with this room
0079   paths = connectingPaths;
0080   foreach (CMapPath *path, paths) {
0081     path->setOpsitePath(nullptr);  // prevents a crash
0082     delete path;
0083   }
0084 
0085   l->getRoomList()->removeAll(this);
0086 
0087   if (textElement)
0088   {
0089     qDebug() << "CMapRoom room delete so delete text element";
0090     getManager()->deleteElement(textElement);
0091   }
0092 }
0093 
0094 void CMapRoom::setLevel(CMapLevel *level)
0095 {
0096   if (getLevel()) getLevel()->getRoomList()->removeAll(this);
0097   level->getRoomList()->append(this);
0098   CMapElement::setLevel(level);
0099 }
0100 
0101 /** This is used to resize the element */
0102 void CMapRoom::resize(QPoint offset,int resizeId)
0103 {
0104   CMapElement::resize(offset,resizeId);
0105 
0106   foreach (CMapPath *path, pathList)
0107 //    if (!path->getSelected())
0108       path->setCords();
0109 
0110   foreach (CMapPath *path, connectingPaths)
0111 //    if (!path->getSelected())
0112       path->setCords();
0113 }
0114 
0115 /** Used to paint the element at a given location and size
0116   * @param p The painer to paint the element to
0117   * @param pos The position to paint the elmenet
0118   * @param size The size the element should be draw 
0119   * @param zone The current zone being viewed */
0120 void CMapRoom::paintElementResize(QPainter *p,QPoint pos,QSize size,CMapZone *)
0121 {
0122     signed int y1,x1,x2,y2;
0123 
0124     x1 = pos.x()+1;
0125     y1 = pos.y()+1;
0126     x2 = pos.x()+size.width()-1;
0127     y2 = pos.y()+size.height()-1;
0128 
0129     // Draw the room
0130     p->setPen(Qt::white);
0131     p->drawLine(x1,y2,x1,y1);
0132     p->drawLine(x1,y1,x2-1,y1);
0133     p->setPen(Qt::black);
0134     p->drawLine(x1,y2,x2,y2);
0135     p->drawLine(x2,y2,x2,y1);
0136 
0137 
0138     // Findout the color to used to draw the room
0139     if (login)
0140     {
0141         p->setBrush(getManager()->getMapData()->loginColor);
0142         p->setPen(getManager()->getMapData()->loginColor);
0143     }
0144     else
0145     {
0146         if (getUseDefaultCol())
0147         {
0148             p->setBrush(getManager()->getMapData()->defaultRoomColor);
0149             p->setPen(getManager()->getMapData()->defaultRoomColor);
0150 
0151         }
0152         else
0153         {
0154             p->setBrush(getColor());
0155             p->setPen(getColor());
0156     }
0157     }
0158 
0159     // Draw the background of the room
0160     p->drawRect(x1+1,y1+1,size.width()-3,size.height()-3);
0161 
0162 }
0163 
0164 void CMapRoom::paint(QPainter *p,CMapZone *currentZone)
0165 {
0166   // This will paint the room
0167   CMapElement::paint(p,currentZone);
0168 
0169   signed int y1,x1;
0170 
0171   x1 = getX()+1;
0172   y1 = getY()+1;
0173 
0174   // If this is the current room the user is in
0175   // then draw the symbol to show that.
0176   if (getCurrentRoom())
0177   {
0178     QColor curColor = getManager()->getMapData()->currentColor;
0179     // If the marker color is similar to the background one, use a different one to ensure that it's seen
0180     if ((!getUseDefaultCol()) && abs (getColor().hue() - curColor.hue()) < 30) curColor.setHsl((curColor.hue() + 180) % 360, curColor.saturation(), curColor.lightness());
0181     p->setPen(curColor);
0182     p->setBrush(curColor);
0183     p->drawEllipse(x1+4,y1+4,getWidth() - 9,getHeight() -9);
0184   }
0185 
0186   // Draw exits
0187   foreach (CMapPath *path, pathList)
0188   {
0189     path->paint(p, currentZone);
0190     if (path->getSrcDir() == UP)
0191     {
0192       p->setPen(Qt::black);
0193       p->setBrush(Qt::black);
0194 
0195       p->drawPoint(x1+4,y1+3);
0196       p->drawPoint(x1+3,y1+4);
0197       p->drawPoint(x1+4,y1+4);
0198       p->drawPoint(x1+5,y1+4);
0199     }
0200 
0201     if (path->getSrcDir() == DOWN)
0202     {
0203       p->setPen(Qt::black);
0204       p->setBrush(Qt::black);
0205 
0206       p->drawPoint(x1+4,y1+getHeight()-5);
0207       p->drawPoint(x1+3,y1+getHeight()-6);
0208       p->drawPoint(x1+4,y1+getHeight()-6);
0209       p->drawPoint(x1+5,y1+getHeight()-6);
0210     }
0211 
0212     if (path->getSrcDir() == SPECIAL)
0213     {
0214       p->setPen(getManager()->getMapData()->specialColor);
0215       p->setBrush(getManager()->getMapData()->specialColor);
0216 
0217       p->drawEllipse(x1+getWidth()-10,y1+5,5,getHeight()-10);
0218     }
0219   }
0220 }
0221 
0222 void CMapRoom::dragPaint(QPoint offset,QPainter *p,CMapZone *)
0223 {
0224   p->setPen(QColor(255, 255, 255, 128));
0225   p->setBrush(QColor(0, 255, 255, 64));
0226     p->drawRect(getX() + offset.x(),getY() + offset.y(),getWidth(),getHeight());
0227 }
0228 
0229 void CMapRoom::lowerPaint(QPainter *p,CMapZone *z)
0230 {
0231     signed int y1,x1;
0232 
0233     x1 = getX()+1-5;
0234     y1 = getY()+1-5;
0235 
0236     p->setPen(getManager()->getMapData()->lowerRoomColor);
0237     QBrush brush(getManager()->getMapData()->lowerRoomColor);
0238     brush.setStyle(Qt::Dense3Pattern);
0239     p->setBrush(brush);
0240     p->drawRect(x1,y1,getWidth()-2,getHeight()-2);
0241 
0242         foreach (CMapPath *path, *getPathList())
0243           path->lowerPaint(p, z);
0244 }
0245 
0246 void CMapRoom::higherPaint(QPainter *p,CMapZone *z)
0247 {
0248     signed int y1,x1;
0249 
0250     x1 = getX()+6;
0251     y1 = getY()+6;
0252 
0253     p->setPen(getManager()->getMapData()->higherRoomColor);
0254     QBrush brush(getManager()->getMapData()->higherRoomColor);
0255     brush.setStyle(Qt::Dense7Pattern);
0256     p->setBrush(brush);
0257     p->drawRect(x1,y1,getWidth()-2,getHeight()-2);
0258 
0259         foreach (CMapPath *path, *getPathList())
0260           path->higherPaint(p, z);
0261 }
0262 
0263 void CMapRoom::setLabel(QString str)
0264 {
0265     label = str;
0266     if (textElement)
0267     {
0268         textElement->setText(str);
0269     }
0270 }
0271 
0272 CMapElement *CMapRoom::copy(void)
0273 {
0274     CMapRoom *room = new CMapRoom (getManager(),getRect(),getLevel());
0275 
0276     room->setColor(color);
0277     room->setDescription(description);
0278     room->setLabel(label);
0279     room->setUseDefaultCol(useDefaultCol);
0280 
0281     QStringList *oldContents = getContentsList();
0282     QStringList *newContents = room->getContentsList();
0283 
0284     for ( QStringList::Iterator it = oldContents->begin(); it != oldContents->end(); ++it )
0285         (*newContents)+=*it;
0286 
0287     room->setLabelPosition(getLabelPosition());
0288 
0289     setCopiedRoom(room);
0290 
0291     return room;
0292 }
0293 
0294 void CMapRoom::addPath (CMapPath *path)
0295 {
0296     pathList.append(path);
0297 }
0298 
0299 CMapPath *CMapRoom::getPathDirection (directionTyp dir,QString specialCmd)
0300 {
0301     CMapPath *path;
0302     if (dir!=SPECIAL)
0303     {
0304         foreach (path, pathList)
0305         {
0306             if (path->getSrcDir()==dir)
0307             {
0308                 return path;
0309             }
0310         }
0311     }
0312     else
0313     {
0314         foreach (path, pathList)
0315         {
0316             if (path->getSrcDir()==dir)
0317             {
0318                 if (path->getSpecialCmd()==specialCmd)
0319                 {
0320                     return path;
0321                 }
0322             }
0323         }
0324     }
0325 
0326     return nullptr;
0327 }
0328 
0329 CMapRoom *CMapRoom::getPathTarget(directionTyp dir,QString specialCmd)
0330 {
0331   CMapPath *path = getPathDirection(dir, specialCmd);
0332   if (!path) return nullptr;
0333   return path->getDestRoom();
0334 }
0335 
0336 directionTyp CMapRoom::bestDirectionToRoom(CMapRoom *room)
0337 {
0338   int x1 = (getHighX() + getX()) / 2;
0339   int y1 = (getHighY() + getY()) / 2;
0340   int x2 = (room->getHighX() + room->getX()) / 2;
0341   int y2 = (room->getHighY() + room->getY()) / 2;
0342   CMapLevel *level1 = getLevel();
0343   CMapLevel *level2 = room->getLevel();
0344 
0345   directionTyp res = SPECIAL;
0346   if (level1 != level2) {
0347     if ((x1 != x2) || (y1 != y2)) res = ::SPECIAL;
0348     else if (level1->getPrevLevel() == level2) res = ::DOWN;
0349     else if (level1->getNextLevel() == level2) res = ::UP;
0350     return res;
0351   }
0352 
0353   double angle = atan2 (x2 - x1, y2 - y1) * 180 / M_PI;
0354   if ((angle <= 22.5) && (angle >= -22.5)) res = ::SOUTH;
0355   else if ((angle <= 67.5) && (angle >= 22.5)) res = ::SOUTHEAST;
0356   else if ((angle <= 112.5) && (angle >= 67.5)) res = ::EAST;
0357   else if ((angle <= 157.5) && (angle >= 112.5)) res = ::NORTHEAST;
0358   else if ((angle <= -22.5) && (angle >= -67.5)) res = ::SOUTHWEST;
0359   else if ((angle <= -67.5) && (angle >= -112.5)) res = ::WEST;
0360   else if ((angle <= -112.5) && (angle >= -157.5)) res = ::NORTHWEST;
0361   else res = ::NORTH;
0362   return res;
0363 }
0364 
0365 CMapRoom::labelPosTyp CMapRoom::getLabelPosition(void)
0366 {
0367     return labelPosition;
0368 }
0369 
0370 void CMapRoom::setLabelPosition(labelPosTyp pos)
0371 {
0372     if (getLabel()=="") pos=HIDE;
0373 
0374     if (pos!=HIDE)
0375     {
0376         labelPosition = pos;
0377         QPoint p;
0378 
0379         QFont font;
0380         if (textElement)
0381         {
0382             font = textElement->getFont();
0383         }
0384         else
0385         {
0386             // FIXME_jp : Needs to be configurable
0387             // font = kapp->font();
0388             font = QFont("times");
0389         }
0390 
0391         QFontMetrics fm(font);
0392         int width = fm.horizontalAdvance(getLabel());
0393         int height = fm.height();
0394 
0395         switch (pos)
0396         {
0397             case CUSTOM    : p = textElement->getLowPos(); break;
0398             case NORTH     : p.setX((getX()+(getWidth()/2)) -(width /2)); p.setY(getY() - height -  10); break;
0399             case NORTHEAST : p.setX(getHighX()+10); p.setY(getY() - height - 10); break;
0400             case EAST      : p.setX(getHighX()+10); p.setY((getY()+(getHeight()/2)) - (height/2)); break;
0401             case SOUTHEAST : p.setX(getHighX()+10); p.setY(getHighY() + 10); break;
0402             case SOUTH     : p.setX((getX()+(getWidth()/2)) -(width /2)); p.setY(getHighY() + 10); break;
0403             case SOUTHWEST : p.setX(getX()-width-10); p.setY(getHighY() + 10); break;
0404             case WEST      : p.setX(getX()-width-10); p.setY((getY()+(getHeight()/2)) - (height/2)); break;
0405             case NORTHWEST : p.setX(getX()-width-10); p.setY(getY() - height -  10); break;
0406             default        : if (textElement)
0407                              {
0408                                 getManager()->deleteElement(textElement);
0409                              }
0410                              textRemove();
0411                              return;
0412         }
0413 
0414         if (!textElement)
0415         {
0416             textElement = CMapElementUtil::createText(getManager(), p, getLevel(), getLabel());
0417             textElement->setLinkElement(this);
0418         }
0419         else
0420         {
0421             QRect rect;
0422             rect.setX(p.x());
0423             rect.setY(p.y());
0424             rect.setWidth(width);
0425             rect.setHeight(height);
0426 
0427             textElement->setRect(rect);
0428         }
0429 
0430     }
0431     else
0432     {
0433         if (textElement)
0434         {
0435             getManager()->deleteElement(textElement);
0436 
0437         }
0438         textRemove();
0439     }
0440 }
0441 
0442 void CMapRoom::setLabelPosition(labelPosTyp pos,CMapText *text)
0443 {
0444     if (getLabel()=="") pos=HIDE;
0445 
0446     if (textElement)
0447     {
0448         getManager()->deleteElement(textElement);
0449     }
0450     textRemove();
0451 
0452     textElement = text; 
0453     textElement->setLinkElement(this);
0454 
0455     setLabelPosition(pos);
0456 }
0457 
0458 void CMapRoom::geometryChanged(void)
0459 {
0460     setLabelPosition(getLabelPosition());
0461 }
0462 
0463 void CMapRoom::textRemove(void)
0464 {
0465     textElement=nullptr;
0466     labelPosition = HIDE;
0467 }
0468 
0469 /** Used to load the properties of the element from a list of properties */
0470 void CMapRoom::loadProperties(KConfigGroup properties)
0471 {
0472     CMapElement::loadProperties(properties);
0473 
0474     setLabel(properties.readEntry("Label",getLabel()));
0475 
0476     setDescription(properties.readEntry("Description",getDescription()));
0477     QColor color=getColor();
0478     color=properties.readEntry("Color",color);
0479 
0480     setColor(color);
0481     setUseDefaultCol(properties.readEntry("DefaultColor",getUseDefaultCol()));
0482     setLabelPosition((CMapRoom::labelPosTyp)properties.readEntry("LabelPos",(int)getLabelPosition()));
0483 
0484     if (properties.hasKey("Current"))
0485     {
0486         bool current = properties.readEntry("Current",getCurrentRoom());
0487         setCurrentRoom(current);
0488     
0489         if (current)
0490         {
0491             getManager()->getActiveView()->playerPositionChanged(this);
0492         }
0493     }
0494 
0495     if (properties.hasKey("Login"))
0496     {
0497         bool login = properties.readEntry("Login",getLoginRoom());
0498         setLoginRoom(login);
0499     }
0500     setRoomID(properties.readEntry("RoomID",m_ID));
0501 
0502     if (properties.hasKey("Contents"))
0503     {
0504         *getContentsList()=properties.readEntry("Contents",QStringList());
0505     }
0506 }
0507 
0508 /** Used to this rooms current room status */
0509 void CMapRoom::setCurrentRoom(bool currentRoom)
0510 {
0511     current = currentRoom;
0512     if (currentRoom)
0513         getManager()->setCurrentRoomWithoutUndo(this);
0514 
0515     getManager()->changedElement(this);
0516 }
0517 
0518 /** Used to this rooms current room status */
0519 void CMapRoom::setLoginRoom(bool loginRoom)
0520 {
0521     login = loginRoom;
0522     if (loginRoom)
0523     {
0524         getManager()->setLoginRoomWithoutUndo(this);
0525     }
0526 
0527     getManager()->changedElement(this);
0528 }
0529 
0530 /** Used to save the properties of the element to a list of properties */
0531 void CMapRoom::saveProperties(KConfigGroup properties)
0532 {
0533     CMapElement::saveProperties(properties);
0534     properties.writeEntry("Label",getLabel());
0535     properties.writeEntry("Description",getDescription());
0536     properties.writeEntry("Color",getColor());
0537     properties.writeEntry("DefaultColor",getUseDefaultCol());
0538     //FIXME_jp : For some reason this was comment out, there must have reason. It needs
0539     //           to be there so there must be a bug somewere else now that it is uncommented
0540     properties.writeEntry("LabelPos",(int)getLabelPosition());
0541     properties.writeEntry("RoomID",getRoomID());
0542     properties.writeEntry("Current",getCurrentRoom());
0543     properties.writeEntry("Login",getLoginRoom());
0544 
0545     if (getContentsList()->count()>0)
0546         properties.writeEntry("Contents",*getContentsList());
0547 }
0548 
0549 /** Used to save the element as an XML object
0550   * @param properties The XML object to save the properties too
0551   * @param doc The XML Document */
0552 void CMapRoom::saveQDomElement(QDomDocument *doc,QDomElement *properties)
0553 {
0554     CMapElement::saveQDomElement(doc,properties);
0555 
0556     writeColor(doc,properties,"Color",getColor());
0557     properties->setAttribute("Label",getLabel());
0558     properties->setAttribute("Description",getDescription());
0559     properties->setAttribute("DefaultColor",getUseDefaultCol());
0560     properties->setAttribute("LabelPos",(int)getLabelPosition());   
0561     properties->setAttribute("RoomID",getRoomID());
0562     properties->setAttribute("Login",getLoginRoom());
0563     if (getLoginRoom())
0564     {
0565         properties->setAttribute("LoginRoom","true");
0566     }
0567     else
0568     {
0569         properties->setAttribute("LoginRoom","false");
0570     }
0571     if (getUseDefaultCol())
0572     {
0573         properties->setAttribute("UseDefaultCol","true");
0574     }
0575     else
0576     {
0577         properties->setAttribute("UseDefaultCol","false");
0578     }
0579 
0580 }
0581 
0582 /** Used to load the properties from a XML object
0583   * @param properties The XML object to load the properties from */
0584 void CMapRoom::loadQDomElement(QDomElement *properties)
0585 {
0586     CMapElement::loadQDomElement(properties);
0587 
0588     setLabel(properties->attribute("Label",getLabel()));
0589     setDescription(properties->attribute("Description",getDescription()));
0590     setUseDefaultCol(readBool(properties,"UseDefaultCol",getUseDefaultCol()));  
0591     setRoomID(readInt(properties,"RoomID",getRoomID()));
0592     setColor(readColor(properties,"Color",getColor()));
0593     setLoginRoom(readBool(properties,"LoginRoom",getLoginRoom()));
0594 }
0595 
0596 /** Used to move the element relative to it's current position */
0597 void CMapRoom::moveBy(QPoint offset)
0598 {
0599     CMapElement::moveBy(offset);
0600 
0601     foreach (CMapPath *path, pathList)
0602         path->setCords();
0603 
0604     foreach (CMapPath *path, connectingPaths)
0605         path->setCords();
0606 }
0607 
0608 void CMapRoom::setRoomID(unsigned int id)
0609 {
0610     if (id > getZone()->m_room_id_count)
0611       getZone()->m_room_id_count = id;
0612       
0613     m_ID = id;
0614 }
0615 
0616 unsigned int CMapRoom::getRoomID(void)
0617 {
0618     return m_ID;
0619 }
0620