diff --git a/documentation/architecture.svg b/documentation/architecture.svg index 9f4af7ed90a7f92a34e33e0d2ac617d44a01e744..90ec08fc6dccd7e2b5b533866976f4b3b89ec8ed 100644 --- a/documentation/architecture.svg +++ b/documentation/architecture.svg @@ -1,3 +1,3 @@ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1688.7907986111109 1234.7222222222222" width="1688.7907986111109" height="1234.7222222222222"><!-- svg-source:excalidraw --><metadata></metadata><defs><style class="style-fonts"> @font-face { font-family: Virgil; src: url(data:font/woff2;base64,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); } - @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,d09GMgABAAAAACK8AA4AAAAAP1QAACJnAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGigbjz4cghIGYACBNBEICuFEx2cLdAABNgIkA4FkBCAFgxgHIBsQMSMDwcYBBKD45sj+KsEmw2kd1g8gHMbB4tgosBqEMm9j+YzUx/FP35QCBY7pm9xpeH5uvZ/LYmzAGkbnoqkxGNGDNnCAtMkpRoGcYtY1oJ5RWId3jTbGCV6F1fDPx3163v0/EQ5Qqx3PFKS+7lTQom/MjVFrerEPLgBQIBq/UFARxtSoygfd/gfw7/+/qiaZ26S1pbZinbLm7Rl2YMVfG0nIlAtIqtm+ouJytSQdJP9KZ710VV9fdysQJkgIcNoA49n1xnRbMBtO/vG0h9NP+IqvaiXAESGCU43xYE9KnpC3pa7v/7dfandC/BIVCSgjJKBEoWLMwgTumTCrDyoApKCArkLtqQWAKQA4ZuMqW6N7orrCxem41rsK4+r/751WofP7xgc1muZQIk7EmNjfIgAIAFQG8uF/AgDGI5N4gIhFUozYOwcBgCyUBro/TcsBnjcdTTOA50NT9XTg+eqa3QA8oQAAE0nly12TF0RGMBAR3n4JBwNaV8ObpYbffvxk8xUhMTA1GVbH1A9hEmKiaqmbJH7gbHI1bAlJva3I1PG0MGgVBUz94/k625v3j2Q3FwKUTJXbRN1i0D4yS7+bgWnHS9Y4dSHvk2mde2Fl0c7CP03gHwDAbtK0zjuuGv7h1rEZAJ6ajQOs+NRN/4UO3I4rMTVYQqOelyTR1IXs6SPEGwDcKFw+jLgcY/hlq7bk3bDx4v1rsfOFeEGRUVDRMLFxcPHwCXgQa+R9SEgpqKj5CxAoVJhwEQ6hCSLavI6LtE4OoRAZTCIsAEMGjFBRngikYoTwE3jCSIxaRUAUp0DDx0EnIMDA5AFthSCoKHVE/gUcq5npAGDwGASpRByCmqJOQ8dQ65hAbsCmIAEOkMctdx7ANIarcuPYCsHHSiEojmjshqmDoK4WQsmoKoaARIQgE4RHMHFklDcfOAmRyQijJlwA4YKIKFyQ7ACYCIL5wITZjjud4TLygKve5etTrQvwP5qqGgDdgedBvrsGALNFoVj+qCq3jkqFiCJEr7oiSMTUmq6QTgLoYx5XqqgYiAlhoBo2PJUAGTJEhHt5egLVCrVfdJ4CTolBwInHzwWjE0TagAKnUwMAgZYzvTDElvcJgFS5MdC5cK8hMWS/hjNzBhgBEp1L67+BPbaZ1l0A228SX/EUSN7zABHgcgFJQu2AQgeUboaEWrAo8ZJpmVhlcMpTpESZep2HqXga/AQZRNSzSOOwL/Rxmf5zYGrCuBvGfO8bl4z6ygVnjTjtlJNOOB4EeVDT1wAQt2JNBqsLc+/J/ptGNMym6TCPPZQHmxTA6gjfMcMCoYcGBR0de7MbuNUEJ5hn03s3p5dWJlSVzMrKzGmstRaGRXBVgqhEupqbnav3FKcp0/RCb39GCCtKU5Rqziyypob7kPk+vBIuZTZZ/pbfI/8VFyvX/r9EFAWAuLbgnr8GP1zzvCu+GwzZEO90MzioG3ckh9rzqFx/ZeyJ5UpJSgDmr1y4aug4Ros3SfJumdcGfNZ7XphQ+6Mg+JrOMB1HeKxGl7F/lTScyaTuCnl+SKdL11sUMBxfHtUfX5Llh6zwPkmOLMCED46r2dl45pmj9JNJv+AqrjJXTGFyca/xSA5efEu0oWnozQgFq13GsPjEqpR1VWU6+NSlj0hw3PiAtXtRDRCvFq+fw/HNvbmdJOPhySNyKm+vW83oPA0AO1Jz8BuP6NaSIMhiB9B3HMBWg103JGFo6OvPqBWv5MmttGxeEh65IUgPvXNC3WZCOsULjfxdaN3440V8Du4PQ3h+dSI7ROusdBw3nWJIw7lxAzTnbuR0oX+5XBBxcHRk6A0ytbswVNdw04fNTS7RujBi6yJM97j8st1Eom7gA/4FpjFJxrT7SLgcIocZB2QrJv3kMM01YdVR9bVQ3WjTa9NCI2qLL4Z7fWXZQOefXkgIj/pgJr2BswueJQmDsAsEDzE1YXS5QzefzEg8RU9k+Imr16hjCO+HqRymIsdj2ulUxb5uEeB2hsv/erlbDtEfrF2ck5cFrmS88umn/dpym4p8d5re+qRSg3CcqCXLWqwqaPVyguDKrPf7IozQXZfTvMQxXVCYxs+onE2RVF9rE2M4wB7hW1AB+Qm0fKtAzUII2+RAx/hAjU28qlzLao7D/txRmoq1eI0WAtWkABDm3MQHDwAnpDchLJPksefTH1di8bYpniLAcFMlH7BSCisY7FBBaAUqC/gzQouHuo7ByrqAHBw3zQk0Ci3fCzZNXLmkJNUrtNAJoLxxhYmxlQ/3Kbe9Me3KDtU7cqjXZX1gF6W4Ccg7mmIIzqzrpwUVWktfl1rMKRV5RjmSv9nhQFtBB3rdH0BvPv9Iv6BWGPWYFTNRUDEkz/Ftu7CaMZUxLXDTiz2P4Wa0p2Kv5zitlmJMA4+iYhypwzO46WuK4foUIhYxTD64moFXUZkXGwX3YMWk4N+qs/xefmuh9lAYetUlQ7pCoPnuBgf0u0DVDIFdv5MXsQhTxJgkRebv2Cf5/jZJUp1TXZNEiQ45jCqHy7x/hbzs4YE4YMtxIX8vMaZfijgQhuX3BwHOhhox3O4pLIKebnB7TCHCbRpiSnDc1ErSXUyDutHTBVmlsiGHK5QdkiHDRWFDRCzA60mWtjAFHeOGdPv2SGwIqneMbbu4qyoOyoEHfXfA4UTRFXgU7ufyocVdfxMiv6v6CP8w5PCLSVr+S4mRtKlUz1bhbDq1p1cKt7RUTI26LJA4KcHrmegGmetby7WShoxj2j1l2GfWGF+dAX6NUHlD857E/Hb/4MFNOARjnCVWu90GqTTUVNcH/KtXTg7lZExXJSodfA2JsM/rSUoqLUfl5KJdgimScXydPe7PntEv3qLAl3YLpq9wrweOg58G8WmCS57MDHjlxtbNsyA6pXpnVWdSnawh7Fduddio32vLNKYQRTaIBomHJQocjA7kLdNMlEbr2GGEMZEoyQZYROx3xVyq7s4tp8LQgkq7LeRjTHsqHnY6gNzf0nZuWhkCKtO425k4rInxrrvV9bqcLK1KvC/gVlNVfBZtcO0uAOuu3GG5e0+6rHOpzLmwfduSuTvY+XUtxm2iXVmoO5YEHUFefZKkgSTFSIy9hdP57cYrr3TA0B69RxBYpCk8mD2hzmq+inz3jhoVscAkL3cmF+7WLqyNiuj06ubqI8KuOyK8bYgtr+Jn1+3aRz93ciVPv2k8zXlryymCs2OrfId4jWFao8QYVkHTH+N3MoB9XvSI8GODvkUhhLX43L+3A46Yfl8x40iT32Lh+JaYc+K+uVZnEnrGtCE7G4bNb+vVZOu95KKM8Rv9N66uBqYr5DXjAEIQ18tR+bkWjJNFsbMXajwwe1zmkNrFZrJYUZ3KfStEjkNyDcZ0sisnhuDC0KJR0BXOLFKjc36oaj6QFEDgQ5TBLFUX2JTX1kALlWbD1c1I1vSDJgWribL4zF6JBkxpk+G3CAc4O1PMLUUYegryCTcfLqzu0jK7oRuu0qG4vST0PII6RQzaGaYeUL2D2+8ExCX3d4hOsuyzZbBv318e6A1Xtp3nu7OjufHKFVXUe9C34qJ4HnWd0gOuek4Xr8fw/SLJxIeDolc9sffs1+sndDCyJsNSj6+mZtK6Sqqn3cbw/qfnRbU4HZbiQI3A9FySEr4K89ezqhPg+Psssfs0lJqX53VTZpKkRijK+iLRug/0H5Cd9ga1QrY2neL4/JqqRVwN7no33ktwDKiYwrnlC1P/cUWDmwhobewr1Yv3lviydrfAV/Pzm/wrp5gfHo+kreTbxY9PFN8WWnCm8qg/86qcIWLR2hoqbhv2h8fNyaB4Z88mJi5fVZhUg2RsyTE9njaGP0+XZEp7CzxdXYgKfIgKPCJ5xfTIktf8qL1IrJsrGjTcjUnJUjFmcKc0SDTl9P5+S3l/pKf2FAGmu0MLaHEkZoNLvBKZbw7T3LZYOkLwuQKlGMLf5Ce7RQR0LPnQZgjEK6M+b0Zz7c46Vz0Gh7MzE1dMYTfVq7l7PuAwu4yKmWdZh6seHYrtVN9OLz7CnucxhogxXEIl52oXCEpnk/NlVzk4zO/Yf0rydcNet8hjuEhMH1MHfnXlCeE0JYlhq6SpbrCFVceXQrQ+ErZc9+KBXLQHF9I9+KNKzvPvSpJd4HFtdKkSj4jujhesDsy5vpuXdluWdflYmgpdrOJdlSRaLNWp/jbkoVgPt+Vtkd8SFyyCkmK4R9Im51KcdLsaAdbnOodyaBEM8V3R+cuDqX5kZXPBVBh79qJ0sh51u6wJeyS/qdu6uy0nCg4gB613WzhwwPUJy2GDwQNXElNINeZ1WT1SzOUrzNWo8H7YFlTrLOsxBi2Wmh3JOzigMh7T6aJEe0wrQ091pQCwV7/2e20/1+dVetQ4QpB8Xh544KT3qAFC5DkM3RGpIgMOcAD7Kvpdie3h7Fd0XNcllXS6KjaEsf3nj9W3lJb8FwP+zTz9pNHkkmesjn6HhVqTR1/t1+IPDqrZ3918sipELnyNK5Ep31J6dH2pjiF6gokxBlGnA+s1T2r6kuP0f1uJBfFol0PF4wbj099PL53/9vrlWGrCSDF90pgUn5wB7sKGRoHjO4CKuaUfT5dTw9oSYWJSs96XNr16S8fH0RkCW9okT0mD7iok6dIPtSFaY3hM8HrRPHAmvR6gjw+SUhlU7Urx4XJlWeYr60Y1sbmEODATwm5IeIO+s/q2G46rY40S/FhxFldfW2RGM221qbSmgy5qjiJbAGouaS1h2l0bMBs8/w4nK6bfJxy6tVzocZIaubdIsh0KWeSQL8qYyjEq6E1vzaTNOYoYgpnaDwypIEDCIjzOKBg0k+x6EevGJZN781U/+SI1UrrAqS03tZJ3xcEQE5Xb3oE3blObPz0jFqFJqlWm5YEDKgGE1mrVTS+S7u8l29v63TqUn2rcVa/V3MwhDoI4S0jGB7Rrj6j9FlgQBHhHI+2J6X1hyPvyqXgRHWfeZUmfKH/JEwu7RugtyY8iDA5H5FL7w1ARgqfKpyh5LUTdF8WWsRfD1xYmLzUDB0amB+IeWRQxHIMyuddvsgfCLcUNbgC+Bvf/FtmVw72GFfkLmWLKh8vJ6o4whgjwWMXiRj2+aUk8bh9MTJq0PY9OFq/m+LM19CWHw4C/g47jq5HZy2X22vRIzDwzlbmGDybkMG+peAy9thLCzrLtaNa95oAnJ4AOQzB9ZtevdBxhKiKHhqM8aqBRM5PWP/NQxxO4EZm3sp6ZxnYxRSuk55SdV3DS67tUaDGN7WFibU11IRrUPoGuu0nT7Xfnd8WGCOxvHvE/V4r3KutXCPbQzVvq4p1aa8aDag0Quu692h8I2gyLN0L09vX3+FcWcxvOpgBmMKtVJbWL6uzVOSttmq7QmLX+96ONbBuS+Gxq16vxYeVz04LcdEr3hYxR3a3fLOufO8mprJ6Uk46MAa1SySrtTkKSuJZcw+yyGceSjStIOlq5Ye+zQea5tO+Y6y8uWkZdCGaNEp7hHCJkXg4ptk2bOCDaSdCxNvvkNuYuP2V4C1jMn48JAd5QD80ajyjxMsyQVgrXk/K9Qj4dyqkF9VdZmz72ElieCLgvBgmT5Tt2VZwvmKhZsJZf7tt7yQBWKBdsmynjp0Idlb+p+jMpZWXnwb9Szr5KD8OXyJ7rcVU7XKypd9uBs3ZdoTdmZ4uJufL2Uw+NtpftbQLh6BVnIkP7CvXwhysp1HQUhUuHbrCoA7syyBZd3fQXi4WObO7ffrKjWVbMl4lW07BbvokMrZtpIwkrZm9MHZbeqejO5oGKX0PynT4OL9BF7N4gLPlnQQKT9lclIQAydsD0xd7hg/5pIu/9DNUh0qckaKH55gINH3QTdv9T38/BWItoWVn7n2RGjZNoty2RDviaUxae+8C9VYcrWisrYCZloGTtgpreto0rxDVVsc708Sz977I3uh+BMIJ2+O/ZVuqYmLzeCX1oWMrfyKVQH+Dhx6uq9jMPyDn2K6V5z1t2Pt0WZNS/4hZD3dAs9yD3BCDUM+TeOATBFZ4b6TC77/wSJUSBPvotNCKdZcWIOZxNX+/Fn+Fuia75xqGq0GCQF/xKqr8TWuDeCvRgHZS42G/sqM65jVdftFZXqBXXNktwuJWJwg+kxpcN833nXsqEz3jW6VlMAF05ZKzLWVEyxiIX//P/c2Phhgx7pLZB3A8QB/4hwqGbnB3C9qwFqR7AKn1EPNZTdXUYHrQ3Og4exDFWy+vCWrIJJguI58ykCxCQpwnsvsNxd0WU3S/1kqUq+tIsp8lhkmuOld0y3798q/zipNanirWSoWgz/du1nVyTHM42OQlYVpgtr7KnqEFMMESfhLTJUCGq41gbbCpS9kmwg8qdclZ78FVJhAKinkgocJZFTGIag4r0JdM8xvvzwKH+c5/3eO5QRq8f2PADlhIzuitMOTQLNQn26PmH3lUTat016kCkVGxgDJIHR/Tnv6+NHnfMQ2+0CDJFSof86EILetXVqIF97DizqgXHMpAcxtU/kjv3965mjJV/XbB7wcws0MLclcbFS6hn39jwM3ultlYHQXL5IMNjr6ArL+H6heGj+3PsPbQfTJWr4e6N36WkV5HKOeUkeKaX3ECgCKOFYf/8Xk5vHO+RKpFyFuFXJ176LUH02QEwmNtNsiuRcqsO61R8ZyJzibjmp+aUOgWvG6sL8LC3M2XFyfkhlALIAY8gnD3M58IZTUQ6ySz1hgwQ7SibqOOBV8HiuYhFEFJUb1fEVAn5n4xCCJw3SwRl0klGkTqTM3tYAgqEMXP6aoU5QQdYx4yMRsuvdKKBPJvOOpQeSYwMcM1P4wFmrntoW+DOnLCfeu97WO85rtUqhx/iHMQzHGHqmQhkgLolf7uJGhyFL9ln0FjQ2nNRHxP8lrvGm7hYKBKK8Sp81gN/8JJJ6qEPVRP7LGjwv9ZQRWFUO88WFlAaSMTLoD8Hgiic3TTbvn/yn6pLxBxSQcNfCilUiOftcKxwzAUsUc08EjI9GHxjGXvwrc3+IvZjjmtjECF3NiCokQUGgbGsoTlfpo0OiYdIjFyRPXGnzASOS79GroeX8xau79iZkSrPJvIMxXpO/+kHFMI189Kv4DkKZfIvSNPHPnlFA3g+380HaFPfTuYe4xGSBgJD3YTpMdv5KGZOAGlBonn/Lk/xKITbYWJI/5KACz5623Sr/cUHkNkWyZtNXePiTabxWlVzN8wuV+kuFXKsZ9j5ybzVxBV/TySthnlmBEsntsrnrjyWtLls7aTKOHb899WKH2TNWT3w8iv8E4UkFWaTHwRzIOK1qDu/1TntzWmm1xzpxfcD0suxPMlP72k7lR+HzPW/ExipZXMexedTSQ3oXhhLjZJIOLwnyCcucgvxC9h8AjLIuIxmp/Z/VO2KOFyTitnldmyhvDDIaY66JWZ8evDVX0vDKeM6bCGe35NsNycZNrIhSFKzAGOqjdVACDfDGbL9HxfJmcETqoEw6OOnKg1kI/3VO5BtDHPO9O1KZNzYOthoD4W6kKP3Vywwg6a1r3Vn11X0aChYbw9cDNk5daGfz4k8nC4m42c3p/o090alZCwufaZNnFkNhoT6iGooA+OgXwfTi0PtBmYmNK/Re6p7wmMker2uUA9kC4oJGqx6MbLDzcTcZAs0YUMDcJPUhwhtZLp3uql7qRxM80CD/UXIAz8RyaRNuxCP+bITzIsgGBefy/AQn+EUluPLZyJKtwpRR0cs/3/keWsYT/fyLolAtvvYepQNf36rlv3RT41uaK+puades1s+1yaAM/05LHgE2aBGG5ephXRncHmg35qWVc9ql9H1w62Cw2A9RZm8wsrxiqlHq/kl9d4BzysMhshXz+kzooT2SJOk/GOrclGoKftI3qrtfR7sFd+elrNq00JbyQ//SDG//P2CInMDDYYiIBxMvhPwaLOjiH59NSOrfYUWkSnWIk+NIT346bk+ryLL0LVU5cpAl4TG2tJW/fftt+CMFekQN659tZRp+EzmZn3nmFxNs9GKk9z5J045W6Cz/STnNtlcz8rOD8NwzshgZT9dQnaTJ5sWpPRm7fueheG08uppDwfc2YmLa/q3Ns/LWajqWdzRIH+ty2HpCeddRhijzHQNvcQeP6L5XP2zT714qwAsG61cpkLVDyJCF17K+69GHe75gojspnGEEJrXFcJoi+m9ck6Qju4YXoQPZzUXzlh9TpdJRXqZfQ6YTi4hp7HxuQwBYmWlOykHdvbt9DNrklnAfuGxopA27e5YZC5U+cAUjP9mYK/zoNSjdgH3YWi1C8Eu1UKLzwx/g+YZ9mZf0T6AjE3krLO/jEzMuKMkR2OZ3CBKM2k2Q4iUeAnhjqVe05YFcN0Xh3sf7aBBYRBYD2AI5oOg6dQOluC7CCgUU1Gk98eeaC4vpFswLLXaezccw4ynZtqYaooTS4Sfwdaf6vEn6bRLmAqcwx9oPVSrpt3MdPL8IX/jscAqWZ+FkUlg1W+K/a64aLUgQyAr8lhFz0TfACyg4oDpvCLyI77WV9+Yoyth3YDmVFuQdkKkDY3ozz/oRus9AZlSZVbbgknFUPZcPEfE+4/Gm3aHNUAWP8QYS8SMlYh9geIPb8smn2C7LNa9bCAtMqwglznaeWk0h2V++te2QEUm6YzpnvNbViEopo14Zj2uZN5+jZsa1nTzy3z/0IxKa8ZSlKMjyOVncZfX/dn3yC/yBKxL2PMk/E06NDwda4okeLSXgH3ssK/HP3+FZyURSJkfdGZQJ2x+yQgB6SDgofyqDDazFE48+tAhGogEdiV1usInXaFxheSJRRqb999RBO7M/4QNDQyz9fxo5B73YangRV5g0jreTthMyqmOAL65FxQ105Kz0jweV440ZqWo0KwChM+LmHHva/r+irQPOAtHb+ublDLuZI+dn5WJ6tQGeeFfbVjzMy3ZC87+JWJ1I4/7bXjtTjBE7nu5pFvdyWPrF3TuL+DNl/swe+MPQtP5wqzlHpEHm/ub7HDXvg8+fsHGZoQN3f/fdUGxIxtqDY2PaqJlEC2Xv7LO4by4MpAcAJ7wRHreDpVA2ErEiLHi+RTCnXTAbeWYYgpnbtYIM1wC9gnD2hcyBIx3k9JL2WgWvDo6LGFJvIUclV/3IiPGDDBKKAVr+9Jof/d4uklmSEiwflxznHVbIdFxy3yIrVuR/T0KIIrdkulTT2+TVG2+E/gHeMQjqq4GNAkY+j9OqKdHWuto1OsUwVIZQFBaSEQonMpGimA+/a2ag8Xq+soHITD1A+Y5H32SQnCZCt2OCD5fauH65G8X5/tDMWxjI1hzdvKVl4S8r9vFYdkd6zRLwzvlHVAcK4+1xOO7PYDmJSLYCfkET68/VRd/5M2cdSWIKAuB4BD1NLBfdKvSuFIb+ts+KguvRXDTy3Oz7ec/AP+MJpUXWr3OfTY2z0jXjcOtvq4qmf9RCCbicEnY9UDj6JL3yHQ/NrGD4BWFzIBM5NWhXyowOBOvVxbJoV0WsJAjGL0HzfWgEciUS54w5YfADr7YB56PIWYyLYh2jLDOCiFGyRe7aZ2joBPsKVdsg5/E86l9RWVRW948yFcffcaNaeYkZU/c/OJD2wixAMo747VZRW07lzPVMFseNAeuJIVlG9pZWzO3RqT92w/fScmjNMNhIDotomwFOAiTheyaWra2WPW5RSDDiVJtTJSDE5zRuNNw0sdKWeeFpSMkpv6h5Py0AHoMpB++Js+dJR/XSHdP650+7G12srOQs5DnX5I6cAf1rz9tfYPWT/Ov/1zrtyHFtjRlNML0WcrMueJn1e5QSapfLt8aa6Jod9RCspzgQJ+Lx1k5fQaibwAFIs98ODwdbGlyu8dzT7F8zeT9RFDjCTmKSYb5D7/mGGmE/hbvUMs76rz/GpJl447IrSgJ7pESpsVXrd0Yvf50oohntZhyPlc+p6Qyts+ld4JNFX+kHi6iFtKakcyLGYLDsF/TCciV3e6DZcV2sn6HuyPu5aUROBycAhNmkXrgQ3HCZGLsL+DbWxO5uneQCEUT38AmdFYATLVG94M18n66gYsNyaiCCBkN2r1DsHdlUXcZFyN5rrJwqQfMc5eROcrloIlPWxmXsHdiLImOWBE+bABaI+eaMjb8b689QxqK+Jv+qNagbek6p6c2ylRxWYTP/L1YkY3BUuRR2EFDq4XnWIxlPTzU8ubG1cUv/j/ofJQfoyudJLAapfPmAW7sWJHy8pdKSpeKa8nVn7tJ8hqquH1fH8fJp47E1h6t4+8J9kXcNcqw8SHt2N5PwELXCxNzSFBiYsSSM7/wfF8dGfrEflC7yNhWP8eMtnA/Hxm7m6Up74pJtzdK5oFxKk6I1y77Y361hwNO7urwkewZ7omKONDnARkpThoe/JwjC1toRiTBsEIZH+L4scLvPMnrpK1GbPOL/f4zAoKW76ZLQwJUsWgSzfz4LbsA3COwzh/7OrZEaP+iTeC1EMggKVDYn4FwRC+cvmTJ0W1PHryVeeTt2Op5vejqb9n4hiEJOpLGINyP1bYbcowlK2PuavexqqT6UC1OAF/REQnlim6ibmDxrIgEaAuMq2isABkrbwGhlZVT4jXXhK3z1+elaptqJlWIVS9NxQPYXheDq7eEZQ/H/QJtdz5yaXo/NzdG2mS6ZNMPE7w2kSO+DliSdmZumo7Wp3Zn1uhiPyx4VJ17vz+I35ZLRBv7mUs/Scx2aZAdsx26OP269XN515gsh8TIjoYQ2N+wt6YoSWPk8S2xrA5JxdWI14Ger0ayuj9cU6D7i0mG+ReX650et0PAvWbJOqWUWhq3+tOktZdvmuKkwsproqIZWhfZIljgx3qxwIwHPETK6YHmnzo33r+R9zYusxY1JK7KnuMhlqV3JjdG/gfHK90eg8mfhcfEk5LlnmSgFTyNIMUPxczqWfqmbh95Y4144Q/Ohzku83e63rNI78dltFbK09/6ocTnQd1G7T8bSkTvjVYEErzZw2nyfshUFXjEl14zkS4gEvgKIkF+SSY+YQP9YcdLZXNk4xWeskcta9Nv7pbeFXXDYSvOMDlRmvwK1s8kwie0htm74s7nUZBKWiv5fzJ/5fju7yo2iPX+fnn7IwFx8UAdR5SPV6xkgZ8PHaqMQyh5qYsJPzLYi1g9CuBm/S8u4KnN2jU7I/n3kftQEpK6xDfQFkg08ch2Bo9nnf/p7WjK2g8Xiy7U9SDrZafuutZ8qeP+GGNvNTme33yoD5rhtK1dbJ9oJihozvrsV33RjRtBb9NXVXY8+//Yn4Y4Wb33Dz71BMiFhNRQ02FTGSPxGZGC/LEuAICJDv8XeQaTu/7umlr0LvSv9RIARHAI/qenwg1b47K36wDB30vcUsE4vQD0LXDW8pvNOMOmaxrJEIE2lYT2APAnwUIFtM4Lbx11SQKS8s4HrfdxayfqPlsNSEsBqHHBC1viosGZm6LnUb5tQ05DVYCoeZmkEuqERPPIqwIEFCPKU8x4gkyAyAYkRgdx5QtNKCYR39kiLB9+qUEphEUDtA4LKhMjtvASSWcfseizehPN+sP7EgfFuQFwwEJA3nINHImgEAJaSQCAGS6fQiBcp0NgdIMhCH89ISiFihBMMgVwdr4AGLWr5DJDvRqzNJgtiEO1Wi0+qkuTXEVv0qxe11YiTLBQqkpg1qsd3OpWRl8WgXAJP87C1x9DHXs0kpGxbbpBNrMMCaFGsrG10Msqtw4N6o1EXUrwM4BaVoULFYg8oEI7UxIWVcaqS5tgBq0HM+Sw8KJZQbVk1WhlqDIqQSCjqfcw); }</style></defs><rect x="0" y="0" width="1688.7907986111109" height="1234.7222222222222" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(181.33333333333303 468.429292929293) rotate(0 496.5 313.5)"><path d="M32 0 C392.22 -1.22, 750.78 -1.96, 961 0 M32 0 C350.37 -2.95, 668.6 -2.73, 961 0 M961 0 C981.11 -0.8, 992.43 10.61, 993 32 M961 0 C982.35 -1.02, 994.77 10.24, 993 32 M993 32 C990.27 180.3, 990.44 329.77, 993 595 M993 32 C993.61 250.68, 993.46 469.57, 993 595 M993 595 C994.01 615.74, 983.64 626.88, 961 627 M993 595 C994.03 614.05, 981.9 627.65, 961 627 M961 627 C646.22 628.26, 332.93 627.51, 32 627 M961 627 C711.11 624.58, 460.9 624.42, 32 627 M32 627 C10.59 626.53, 0.77 616.89, 0 595 M32 627 C9.28 624.92, -0.3 617.43, 0 595 M0 595 C0.03 426.99, -0.11 258.91, 0 32 M0 595 C-1.21 479.68, -1.88 365.05, 0 32 M0 32 C1.86 10.09, 9.1 -1, 32 0 M0 32 C0.31 11.97, 10.76 0.02, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(519.9999999999998 397.3181818181819) rotate(0 98.72837829589844 35)"><text x="0" y="24.668" font-family="Virgil, Segoe UI Emoji" font-size="28px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">MainWindow.cpp</text><text x="0" y="59.668" font-family="Virgil, Segoe UI Emoji" font-size="28px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QMainWindow)</text></g><g stroke-linecap="round"><g transform="translate(180.33333333333303 529.4292929292931) rotate(0 497 -1)"><path d="M-0.62 0.95 C165.13 0.91, 827.6 -0.38, 993.57 -0.8 M1.25 0.4 C166.89 0.12, 826.77 -1.62, 992.4 -2.3" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(602.7777777777776 480.429292929293) rotate(0 55.43994903564453 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">TopBar.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QToolBar)</text></g><g stroke-linecap="round" transform="translate(210.33333333333303 482.429292929293) rotate(0 117 17)"><path d="M8.5 0 C82.95 -0.86, 159.8 -1.13, 225.5 0 M8.5 0 C71.09 -0.8, 134.25 -1.35, 225.5 0 M225.5 0 C232.33 0.33, 232.7 2.76, 234 8.5 M225.5 0 C233.15 -1.94, 232.78 3.56, 234 8.5 M234 8.5 C234.21 14.51, 234.75 16.2, 234 25.5 M234 8.5 C234.01 14.79, 233.84 21.05, 234 25.5 M234 25.5 C234.43 31.84, 231.54 35.7, 225.5 34 M234 25.5 C235.6 32.53, 230.89 33.21, 225.5 34 M225.5 34 C143.1 32.42, 65.1 32.35, 8.5 34 M225.5 34 C151.33 35.67, 76.52 36.47, 8.5 34 M8.5 34 C1.77 32.02, 1.93 31.63, 0 25.5 M8.5 34 C3.25 34.52, 1.32 30.23, 0 25.5 M0 25.5 C0.55 19.94, -1 13.59, 0 8.5 M0 25.5 C-0.13 21.51, -0.72 16.51, 0 8.5 M0 8.5 C1.94 3.8, 4.48 -0.8, 8.5 0 M0 8.5 C1.85 3.76, 3.37 -0.05, 8.5 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(217.33333333333303 491.429292929293) rotate(0 0.5 10)"><path d="M0.25 0 C0.42 0.01, 0.61 -0.02, 0.75 0 M0.25 0 C0.35 0, 0.45 0.01, 0.75 0 M0.75 0 C0.89 -0.04, 0.36 0.81, 1 0.25 M0.75 0 C1.55 0.25, 1.22 -0.63, 1 0.25 M1 0.25 C1 7.43, 1.16 12.83, 1 19.75 M1 0.25 C1.04 6.11, 1.06 12.31, 1 19.75 M1 19.75 C1.88 18.99, 0.8 19.82, 0.75 20 M1 19.75 C1.15 20.78, 1.32 19.55, 0.75 20 M0.75 20 C0.64 20.01, 0.47 20, 0.25 20 M0.75 20 C0.64 19.99, 0.54 20.01, 0.25 20 M0.25 20 C-0.51 19.6, 0.64 20.51, 0 19.75 M0.25 20 C0.6 21.07, 0.74 19.62, 0 19.75 M0 19.75 C-0.27 15.59, 0.89 10.28, 0 0.25 M0 19.75 C-0.15 15.03, 0.3 11.21, 0 0.25 M0 0.25 C0.96 -0.63, 0.37 0.04, 0.25 0 M0 0.25 C-1.04 -0.02, 0.34 1.02, 0.25 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(229.33333333333303 372.429292929293) rotate(0 -1 53.5)"><path d="M-0.81 -1.05 C-1.22 16.8, -1.36 89.29, -1.4 107.47 M0.96 1.01 C0.36 18.47, -1.65 88.06, -2.03 105.59" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(229.33333333333303 372.429292929293) rotate(0 -1 53.5)"><path d="M-9.97 81.88 C-8.59 92.11, -2.98 101.84, -2.03 105.59 M-9.97 81.88 C-6.47 90.15, -4.54 100.94, -2.03 105.59" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(229.33333333333303 372.429292929293) rotate(0 -1 53.5)"><path d="M7.13 82.33 C1.89 92.27, 0.88 101.83, -2.03 105.59 M7.13 82.33 C4.08 90.57, -0.53 101.19, -2.03 105.59" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(149.33333333333303 347.429292929293) rotate(0 87.659912109375 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">LevelNameEdit.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QLineEdit)</text></g><g stroke-linecap="round" transform="translate(1063.333333333333 486.429292929293) rotate(0 47.5 12)"><path d="M6 0 C34.28 0.89, 60.18 0.43, 89 0 M6 0 C25.62 0.6, 43.35 0.53, 89 0 M89 0 C94.69 0.9, 93.44 1.88, 95 6 M89 0 C92.78 0.44, 96.27 1.45, 95 6 M95 6 C93.88 9.47, 95.27 10.92, 95 18 M95 6 C95.28 9.11, 95.1 13.08, 95 18 M95 18 C94.21 21.66, 93.22 22.3, 89 24 M95 18 C96.62 23.93, 91.93 23.49, 89 24 M89 24 C56.56 26.15, 25.69 22.71, 6 24 M89 24 C58.42 24.22, 27.9 24.91, 6 24 M6 24 C1.19 22.28, 1.69 21.82, 0 18 M6 24 C2.56 23.95, 2.28 23.17, 0 18 M0 18 C-0.32 13.43, 1.18 8.69, 0 6 M0 18 C-0.43 13.94, 0.08 10.5, 0 6 M0 6 C-1.16 0.67, 0.99 1.82, 6 0 M0 6 C2.11 3.57, 0.77 -2.16, 6 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1085.333333333333 488.429292929293) rotate(0 23.97998046875 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Save</text></g><g stroke-linecap="round"><g transform="translate(1242.333333333333 488.429292929293) rotate(0 -40.5 2)"><path d="M0.21 0.91 C-13.54 1.66, -68.62 4.36, -81.99 4.83 M-1.14 0.34 C-14.57 0.73, -66.61 2.39, -79.79 3.15" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1242.333333333333 488.429292929293) rotate(0 -40.5 2)"><path d="M-56.69 -6.4 C-63.1 -4.72, -71.17 1.88, -79.79 3.15 M-56.69 -6.4 C-63.31 -3.12, -69.07 -0.07, -79.79 3.15" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1242.333333333333 488.429292929293) rotate(0 -40.5 2)"><path d="M-55.96 10.69 C-62.66 6.49, -70.99 7.21, -79.79 3.15 M-55.96 10.69 C-62.69 9.23, -68.65 7.53, -79.79 3.15" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1247.333333333333 477.429292929293) rotate(0 129.68988037109375 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">SaveButton.cpp (QButton)</text></g><g stroke-linecap="round" transform="translate(1005.333333333333 484.429292929293) rotate(0 13.5 17.5)"><path d="M6.75 0 C9.92 -0.2, 16.31 1.38, 20.25 0 M6.75 0 C11.62 -0.38, 16.32 -0.58, 20.25 0 M20.25 0 C26.35 -1.97, 28.5 1.66, 27 6.75 M20.25 0 C24.01 -1.02, 27.24 2.84, 27 6.75 M27 6.75 C28.85 14.28, 28.08 22.09, 27 28.25 M27 6.75 C26.92 14.38, 27.65 22.43, 27 28.25 M27 28.25 C26.26 31.42, 22.96 35.3, 20.25 35 M27 28.25 C29.18 33.03, 25.2 33.24, 20.25 35 M20.25 35 C15.67 35.81, 12.98 35.93, 6.75 35 M20.25 35 C16.03 34.72, 10.87 34.5, 6.75 35 M6.75 35 C2.9 34.03, -0.39 33.16, 0 28.25 M6.75 35 C0.73 33.52, -2.27 30.99, 0 28.25 M0 28.25 C1.12 23.57, 1.49 15.7, 0 6.75 M0 28.25 C0.53 21.91, 0.3 15.73, 0 6.75 M0 6.75 C0.21 2.02, 1.34 -0.13, 6.75 0 M0 6.75 C-0.3 1.59, 1.63 1.72, 6.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1012.333333333333 489.429292929293) rotate(0 6.5 12.5)"><text x="6.5" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">+</text></g><g stroke-linecap="round" transform="translate(912.333333333333 484.429292929293) rotate(0 40.5 17.5)"><path d="M8.75 0 C22.56 0.4, 37.31 -1.91, 72.25 0 M8.75 0 C23.05 -1.57, 38.12 0.11, 72.25 0 M72.25 0 C79.86 -0.3, 79.84 2.62, 81 8.75 M72.25 0 C78.7 -1.52, 83.27 4.93, 81 8.75 M81 8.75 C80.09 13.85, 80.67 21.49, 81 26.25 M81 8.75 C81.41 11.99, 80.31 16.06, 81 26.25 M81 26.25 C80.07 33.14, 79.58 34.9, 72.25 35 M81 26.25 C80.75 30.39, 78.08 34.73, 72.25 35 M72.25 35 C51.55 36.58, 32.98 33.29, 8.75 35 M72.25 35 C48.97 35.89, 24.15 35.79, 8.75 35 M8.75 35 C4.36 35.12, -0.4 31.08, 0 26.25 M8.75 35 C3.76 33.6, 1.1 34.33, 0 26.25 M0 26.25 C-1.35 23.1, 1.08 17.8, 0 8.75 M0 26.25 C0.84 21.29, 0.31 17.23, 0 8.75 M0 8.75 C-1.1 1.96, 3.44 -0.83, 8.75 0 M0 8.75 C-0.18 4.03, 2.99 -1.76, 8.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(926.8633397420244 489.429292929293) rotate(0 25.969993591308594 12.5)"><text x="25.969993591308594" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">100%</text></g><g stroke-linecap="round" transform="translate(872.333333333333 483.429292929293) rotate(0 14.5 17.5)"><path d="M7.25 0 C10.22 0.81, 16.13 0.62, 21.75 0 M7.25 0 C10.45 0.04, 13.83 -0.2, 21.75 0 M21.75 0 C28.53 -1.66, 30.01 3.94, 29 7.25 M21.75 0 C25.25 -2.12, 27.32 2.65, 29 7.25 M29 7.25 C27.46 15.36, 29.95 22.12, 29 27.75 M29 7.25 C29.49 11.1, 29 15.36, 29 27.75 M29 27.75 C30.06 31.65, 24.8 35.36, 21.75 35 M29 27.75 C30.26 30.8, 26.27 32.76, 21.75 35 M21.75 35 C15.99 33.78, 11.09 33.83, 7.25 35 M21.75 35 C15.58 34.65, 9.83 34.46, 7.25 35 M7.25 35 C3.59 36.96, -1.4 33.4, 0 27.75 M7.25 35 C4.66 34.8, 1.38 33.03, 0 27.75 M0 27.75 C-1.77 20.42, 0.62 11.76, 0 7.25 M0 27.75 C-0.43 21.36, -0.19 15.55, 0 7.25 M0 7.25 C0.64 1.25, 0.77 1.31, 7.25 0 M0 7.25 C1.24 3.09, 4.53 0.82, 7.25 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(882.723340352376 488.429292929293) rotate(0 4.109992980957031 12.5)"><text x="4.109992980957031" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">-</text></g><g stroke-linecap="round"><g transform="translate(1025.333333333333 418.429292929293) rotate(0 0.5 33.5)"><path d="M-0.62 -0.01 C-0.55 11.31, 0.02 56.24, 0.23 67.4 M1.26 -1.07 C1.73 9.93, 2.79 53.94, 2.54 65.49" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1025.333333333333 418.429292929293) rotate(0 0.5 33.5)"><path d="M-6.11 42.04 C-3.77 47.5, -0.6 54.94, 2.54 65.49 M-6.11 42.04 C-2.46 49.71, -1.44 56.21, 2.54 65.49" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1025.333333333333 418.429292929293) rotate(0 0.5 33.5)"><path d="M10.99 41.96 C8.45 47.36, 6.73 54.82, 2.54 65.49 M10.99 41.96 C9.59 49.67, 5.56 56.2, 2.54 65.49" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(948.333333333333 390.429292929293) rotate(0 -1.5 45)"><path d="M0.31 -0.19 C-0.53 14.85, -3.52 75.53, -3.92 90.75 M-0.99 -1.34 C-1.55 13.32, -1.46 73.9, -1.7 89.03" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(948.333333333333 390.429292929293) rotate(0 -1.5 45)"><path d="M-10.09 65.48 C-7.04 73.14, -2.17 85.36, -1.7 89.03 M-10.09 65.48 C-5.72 74.54, -2.43 83.73, -1.7 89.03" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(948.333333333333 390.429292929293) rotate(0 -1.5 45)"><path d="M7.01 65.59 C3.37 73.25, 1.54 85.43, -1.7 89.03 M7.01 65.59 C4.61 74.74, 1.14 83.9, -1.7 89.03" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(857.333333333333 427.429292929293) rotate(0 12.5 27)"><path d="M-0.25 -0.42 C3.93 8.8, 21.72 45.57, 25.74 54.77 M1.81 -1.68 C5.85 7.24, 21.12 43.96, 25.18 53.04" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(857.333333333333 427.429292929293) rotate(0 12.5 27)"><path d="M8.05 34.83 C13.31 42.52, 21.32 45.8, 25.18 53.04 M8.05 34.83 C13.65 41.12, 20.02 48.33, 25.18 53.04" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(857.333333333333 427.429292929293) rotate(0 12.5 27)"><path d="M23.77 28.08 C23.46 38.12, 25.93 43.77, 25.18 53.04 M23.77 28.08 C23.58 36.73, 24.22 46.39, 25.18 53.04" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(975.333333333333 397.429292929293) rotate(0 142.2398681640625 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ZoomInButton.cpp (QButton)</text></g><g transform="translate(919.333333333333 368.429292929293) rotate(0 154.099853515625 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ZoomInfoBUtton.cpp (QButton)</text></g><g transform="translate(739.333333333333 400.429292929293) rotate(0 98.07991027832031 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ZoomOutBUtton.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic"> (QButton)</text></g><g stroke-linecap="round" transform="translate(908.333333333333 528.4292929292931) rotate(0 132.5 282.5)"><path d="M32 0 C107.68 -0.2, 181.93 -0.74, 233 0 M32 0 C84.58 -0.32, 139.55 0.62, 233 0 M233 0 C254.72 0.92, 264.11 9.95, 265 32 M233 0 C252.46 0, 264.98 12.59, 265 32 M265 32 C263.46 146.81, 263.79 261.73, 265 533 M265 32 C264.71 216.17, 264.44 399.83, 265 533 M265 533 C264.79 556.25, 253.75 564.54, 233 565 M265 533 C263.43 553.47, 254.63 565.31, 233 565 M233 565 C181.87 565.95, 131.39 567.04, 32 565 M233 565 C163.75 564.45, 93.71 565.49, 32 565 M32 565 C11.87 566.97, 1.46 553.94, 0 533 M32 565 C11.74 566.93, 0.6 554.32, 0 533 M0 533 C0.22 423.53, -0.28 314.91, 0 32 M0 533 C0.18 386.7, 0.13 240.44, 0 32 M0 32 C1.34 10.17, 11.54 1.36, 32 0 M0 32 C1.77 12.9, 12.25 -0.5, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(1223.333333333333 582.4292929292931) rotate(0 -23 -1.4999999999999858)"><path d="M-0.37 -0.23 C-8.08 -0.87, -38.83 -2.82, -46.38 -3.35 M0.44 -0.83 C-7.08 -1.44, -37.63 -2.46, -45.34 -2.83" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1223.333333333333 582.4292929292931) rotate(0 -23 -1.4999999999999858)"><path d="M-23.38 -9.83 C-29.77 -8.69, -35.99 -5.47, -45.34 -2.83 M-23.38 -9.83 C-28.55 -8.18, -32.93 -6.81, -45.34 -2.83" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1223.333333333333 582.4292929292931) rotate(0 -23 -1.4999999999999858)"><path d="M-24.02 5.92 C-30.3 2.77, -36.34 1.69, -45.34 -2.83 M-24.02 5.92 C-29.02 4.08, -33.27 1.95, -45.34 -2.83" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1225.333333333333 568.4292929292931) rotate(0 77.17992401123047 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">TileSelector.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QScrollArea)</text></g><g stroke-linecap="round" transform="translate(180.33333333333303 533.4292929292931) rotate(0 363 279.5)"><path d="M32 0 C215.92 1.83, 398.86 2.46, 694 0 M32 0 C180.91 0.52, 329.24 0.39, 694 0 M694 0 C714.71 1.49, 727.21 9.49, 726 32 M694 0 C713.4 -1.3, 728.05 11.18, 726 32 M726 32 C723.76 180.22, 724.95 328.51, 726 527 M726 32 C725.6 187.45, 725.35 343.49, 726 527 M726 527 C727.77 546.98, 713.79 560.64, 694 559 M726 527 C724.33 547.44, 716.28 559.42, 694 559 M694 559 C523.33 555.73, 351.72 556.14, 32 559 M694 559 C519.52 556.36, 345.02 556.09, 32 559 M32 559 C8.95 560.86, 1.46 549.67, 0 527 M32 559 C8.93 559.29, 2.04 546.92, 0 527 M0 527 C-1.75 411.71, -0.93 296.78, 0 32 M0 527 C-1.1 389.49, -1.21 251.32, 0 32 M0 32 C-0.11 9.35, 9.88 0.55, 32 0 M0 32 C0.53 12.21, 12.51 -0.56, 32 0" stroke="#e03131" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(512.333333333333 1130.429292929293) rotate(0 0 -16.5)"><path d="M-0.52 -0.22 C-0.41 -5.75, 0.34 -27.1, 0.47 -32.65 M0.22 -0.81 C0.31 -6.27, 0.31 -28.04, 0.28 -33.44" stroke="#e03131" stroke-width="1" fill="none"></path></g><g transform="translate(512.333333333333 1130.429292929293) rotate(0 0 -16.5)"><path d="M5.96 -17.94 C4.03 -21.41, 3.36 -25.88, 0.28 -33.44 M5.96 -17.94 C4.57 -20.88, 3.41 -24.45, 0.28 -33.44" stroke="#e03131" stroke-width="1" fill="none"></path></g><g transform="translate(512.333333333333 1130.429292929293) rotate(0 0 -16.5)"><path d="M-5.33 -17.92 C-4.24 -21.34, -1.87 -25.81, 0.28 -33.44 M-5.33 -17.92 C-4.39 -20.85, -3.22 -24.43, 0.28 -33.44" stroke="#e03131" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(454.33333333333303 1133.429292929293) rotate(0 74.98992156982422 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">LevelView.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QGraphicsView)</text></g><g stroke-linecap="round" transform="translate(315.33333333333303 578.4292929292931) rotate(0 241 228.5)"><path d="M32 0 C146.33 -1.42, 257.76 -0.74, 450 0 M32 0 C115.45 1.81, 200.12 1.28, 450 0 M450 0 C471.46 -0.74, 482.45 8.99, 482 32 M450 0 C471.62 -1.64, 480.4 12.52, 482 32 M482 32 C480.83 137.55, 482.65 241.93, 482 425 M482 32 C481.31 143.38, 481.08 253.68, 482 425 M482 425 C483.61 444.62, 472.21 457.89, 450 457 M482 425 C483.83 445.93, 470.94 456.08, 450 457 M450 457 C293.51 457.25, 135.32 457.52, 32 457 M450 457 C297.48 456.29, 143.84 456.54, 32 457 M32 457 C11.7 455.78, 1 448.29, 0 425 M32 457 C9.59 455.68, 2.19 444.24, 0 425 M0 425 C0.5 336.06, 0.98 247.97, 0 32 M0 425 C-0.88 281.81, -0.96 139.85, 0 32 M0 32 C1.23 12.56, 12.45 -0.4, 32 0 M0 32 C-1.03 11.67, 9 1.82, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(738.333333333333 1131.429292929293) rotate(0 -1 -48)"><path d="M-1.1 -1.19 C-1.57 -17.1, -1.85 -80.14, -2.02 -95.86 M0.52 0.8 C-0.18 -14.85, -2.4 -77.84, -2.98 -94.24" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(738.333333333333 1131.429292929293) rotate(0 -1 -48)"><path d="M6.4 -71.07 C1.06 -79.68, -0.15 -88.38, -2.98 -94.24 M6.4 -71.07 C3.17 -78.61, 0.8 -86.65, -2.98 -94.24" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(738.333333333333 1131.429292929293) rotate(0 -1 -48)"><path d="M-10.69 -70.46 C-9.77 -79.14, -4.72 -88.06, -2.98 -94.24 M-10.69 -70.46 C-8.09 -78.14, -4.63 -86.39, -2.98 -94.24" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(669.333333333333 1135.429292929293) rotate(0 82.77991485595703 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">LevelScene.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QGraphicsScene)</text></g><g stroke-linecap="round" transform="translate(320.33333333333303 588.4292929292931) rotate(0 21.5 18.5)"><path d="M9.25 0 C20.01 0.76, 26 0.03, 33.75 0 M9.25 0 C19.41 -0.24, 28.62 0.61, 33.75 0 M33.75 0 C40.46 1.11, 42.64 3.02, 43 9.25 M33.75 0 C37.82 1.09, 45.27 3.31, 43 9.25 M43 9.25 C43.43 14.75, 41.78 17.92, 43 27.75 M43 9.25 C42.23 14.12, 42.47 17.97, 43 27.75 M43 27.75 C42.57 33.29, 38.49 35.69, 33.75 37 M43 27.75 C42.31 36, 39.42 35.78, 33.75 37 M33.75 37 C27.37 37.9, 18.55 36.99, 9.25 37 M33.75 37 C27.4 37.24, 20.28 36.69, 9.25 37 M9.25 37 C3.16 35.98, -0.62 34.77, 0 27.75 M9.25 37 C4.45 38.28, 0.77 35.29, 0 27.75 M0 27.75 C-0.84 21.83, -1.11 18.45, 0 9.25 M0 27.75 C-0.9 22.6, -0.63 17.73, 0 9.25 M0 9.25 C1.28 2.3, 2.36 0.79, 9.25 0 M0 9.25 C-2.17 0.79, 1.37 -1.65, 9.25 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(366.33333333333303 590.4292929292931) rotate(0 19.5 17.5)"><path d="M8.75 0 C14.48 0.81, 22.09 1.13, 30.25 0 M8.75 0 C12.41 -0.36, 17.27 -0.4, 30.25 0 M30.25 0 C34.66 -1.31, 38.4 4.72, 39 8.75 M30.25 0 C35.58 -1.22, 38.69 2.57, 39 8.75 M39 8.75 C38.03 13.32, 38.56 17.7, 39 26.25 M39 8.75 C38.91 14.66, 39.09 20.93, 39 26.25 M39 26.25 C38.38 32.93, 37.27 36.11, 30.25 35 M39 26.25 C39.77 33.46, 35.99 33.98, 30.25 35 M30.25 35 C20.98 36.73, 13.64 35.46, 8.75 35 M30.25 35 C22.23 34.84, 16.11 34.56, 8.75 35 M8.75 35 C2.19 35.79, -1.89 30.09, 0 26.25 M8.75 35 C1.2 33.35, 2.23 34.3, 0 26.25 M0 26.25 C1.13 21.77, 0.87 18.25, 0 8.75 M0 26.25 C0.17 20.64, 0.41 15.47, 0 8.75 M0 8.75 C0.37 1, 0.95 -0.63, 8.75 0 M0 8.75 C-2.27 1.68, 4.22 0.85, 8.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(407.33333333333303 592.4292929292931) rotate(0 19 17.5)"><path d="M8.75 0 C12.21 -2.07, 17.95 -1.52, 29.25 0 M8.75 0 C16.34 -0.65, 25.62 -0.32, 29.25 0 M29.25 0 C35.97 -0.96, 38.17 2.3, 38 8.75 M29.25 0 C33.65 0.31, 37.44 3.84, 38 8.75 M38 8.75 C36.31 13.46, 36.3 18.34, 38 26.25 M38 8.75 C37.77 15.63, 37.75 20.41, 38 26.25 M38 26.25 C38.81 33.71, 34.44 36.29, 29.25 35 M38 26.25 C36.95 33.87, 35.7 34.47, 29.25 35 M29.25 35 C23.99 34.96, 19.58 35.62, 8.75 35 M29.25 35 C21.64 35.48, 13.28 35.95, 8.75 35 M8.75 35 C3.6 36.06, -0.03 32.15, 0 26.25 M8.75 35 C5.01 36.72, 1.66 32.54, 0 26.25 M0 26.25 C-0.4 20.69, -0.62 14.43, 0 8.75 M0 26.25 C0.97 20.51, -0.01 14.56, 0 8.75 M0 8.75 C-1.06 2.61, 1.97 -0.09, 8.75 0 M0 8.75 C0.27 2.26, 2.31 1.34, 8.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(443.33333333333303 593.4292929292931) rotate(0 23.5 17)"><path d="M8.5 0 C17.98 -0.54, 28.48 -0.79, 38.5 0 M8.5 0 C19.1 1.21, 28.52 0.08, 38.5 0 M38.5 0 C42.26 -1.06, 46.69 1.89, 47 8.5 M38.5 0 C44.07 0.27, 46.34 2.23, 47 8.5 M47 8.5 C46.21 15.46, 47.84 21.78, 47 25.5 M47 8.5 C47.86 14.93, 46.52 21.43, 47 25.5 M47 25.5 C45.53 32.33, 42.39 35.3, 38.5 34 M47 25.5 C46.76 33.3, 44.05 32.47, 38.5 34 M38.5 34 C26.79 33.78, 16.8 33.96, 8.5 34 M38.5 34 C27.54 33.62, 17.45 34.1, 8.5 34 M8.5 34 C2.5 34.19, -1.45 32.42, 0 25.5 M8.5 34 C0.87 34.71, -0.54 31.19, 0 25.5 M0 25.5 C-1.11 20.88, -0.96 15.77, 0 8.5 M0 25.5 C0.22 22.14, 0.65 18.26, 0 8.5 M0 8.5 C1.52 1.2, 3.35 -0.48, 8.5 0 M0 8.5 C0.5 1.77, 2.59 1.99, 8.5 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(90.33333333333303 598.4292929292931) rotate(0 114.5 3.5)"><path d="M-0.45 0.03 C37.84 1.39, 190.79 5.94, 229.13 7.13 M1.52 -1.01 C39.7 0.66, 190.32 7.14, 228.25 8.74" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(90.33333333333303 598.4292929292931) rotate(0 114.5 3.5)"><path d="M204.41 16.28 C210.51 14.68, 216.69 13.51, 228.25 8.74 M204.41 16.28 C211.84 13.8, 219.78 11.53, 228.25 8.74" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(90.33333333333303 598.4292929292931) rotate(0 114.5 3.5)"><path d="M205.14 -0.8 C210.91 1.89, 216.9 5.01, 228.25 8.74 M205.14 -0.8 C212.18 2.06, 219.89 5.13, 228.25 8.74" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(10.33333333333303 578.4292929292931) rotate(0 111.31987762451172 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Tile.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QGraphicsPixmapItem)</text></g><g stroke-linecap="round" transform="translate(922.4242424242425 541.7929292929294) rotate(0 39.545454545454504 38.18181818181817)"><path d="M19.09 0 C31.99 0.05, 47.15 -0.53, 60 0 M19.09 0 C29.75 0.09, 39.48 -0.85, 60 0 M60 0 C70.78 -0.88, 78.34 7.86, 79.09 19.09 M60 0 C74.4 -2.27, 77.32 8.05, 79.09 19.09 M79.09 19.09 C80.58 28.26, 77.27 36.91, 79.09 57.27 M79.09 19.09 C79.94 28.61, 79.51 37.47, 79.09 57.27 M79.09 57.27 C79.29 69.54, 73.18 75.68, 60 76.36 M79.09 57.27 C77.93 70.21, 73.15 75.2, 60 76.36 M60 76.36 C48.22 76.64, 36.6 74.93, 19.09 76.36 M60 76.36 C45.42 76.38, 28.85 75.34, 19.09 76.36 M19.09 76.36 C5.78 75.7, 1.48 71.62, 0 57.27 M19.09 76.36 C7.67 76.59, 1.84 68.94, 0 57.27 M0 57.27 C1.15 50.14, 0.65 40.5, 0 19.09 M0 57.27 C0.89 49.78, -0.19 41.24, 0 19.09 M0 19.09 C1.96 5.63, 7.56 -1.36, 19.09 0 M0 19.09 C0.71 8.1, 6.47 0.09, 19.09 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(1014.2424242424242 544.5202020202021) rotate(0 44.09090909090912 39.09090909090909)"><path d="M19.55 0 C31.27 1.47, 41.22 -0.04, 68.64 0 M19.55 0 C30.45 0.13, 39.41 -0.6, 68.64 0 M68.64 0 C83.62 -0.73, 89.38 5.16, 88.18 19.55 M68.64 0 C82.38 1.74, 88.28 6.61, 88.18 19.55 M88.18 19.55 C88.44 29.55, 88.97 39.15, 88.18 58.64 M88.18 19.55 C88.86 30.86, 87.55 41.71, 88.18 58.64 M88.18 58.64 C86.87 73.14, 81.14 78.81, 68.64 78.18 M88.18 58.64 C90.11 71.8, 83.64 77.52, 68.64 78.18 M68.64 78.18 C50.29 76.91, 30.26 79.58, 19.55 78.18 M68.64 78.18 C58.95 78.16, 48.2 78.52, 19.55 78.18 M19.55 78.18 C6.42 77.91, -1.93 73.64, 0 58.64 M19.55 78.18 C5.16 76.73, 1.25 73.78, 0 58.64 M0 58.64 C-0.15 44.9, -1.77 29.35, 0 19.55 M0 58.64 C-0.53 47.68, -0.01 39.17, 0 19.55 M0 19.55 C0.14 6.1, 5.94 -0.56, 19.55 0 M0 19.55 C1.96 5.38, 6.93 1.77, 19.55 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(931.5151515151517 629.0656565656567) rotate(0 37.727272727272634 46.81818181818181)"><path d="M18.86 0 C28.49 -1.64, 41.56 1.46, 56.59 0 M18.86 0 C32.64 0.5, 45.79 -0.05, 56.59 0 M56.59 0 C68.38 1.18, 73.81 5.68, 75.45 18.86 M56.59 0 C67.39 0.5, 77.53 6.45, 75.45 18.86 M75.45 18.86 C77 33.49, 75.66 51.63, 75.45 74.77 M75.45 18.86 C75.63 37.14, 76.59 53.14, 75.45 74.77 M75.45 74.77 C75.74 89.12, 67.65 92, 56.59 93.64 M75.45 74.77 C74.97 87.93, 70.99 94.76, 56.59 93.64 M56.59 93.64 C46.03 93.4, 29.78 92.11, 18.86 93.64 M56.59 93.64 C43.36 94.39, 30.19 93.63, 18.86 93.64 M18.86 93.64 C4.94 93.41, 1.49 86.93, 0 74.77 M18.86 93.64 C7.83 93.32, -1.17 87.17, 0 74.77 M0 74.77 C2.1 57.55, 0.34 38.86, 0 18.86 M0 74.77 C-1.16 57.05, 0.43 41.23, 0 18.86 M0 18.86 C1.7 5.85, 5.21 0.68, 18.86 0 M0 18.86 C-1.03 6.63, 4.97 1, 18.86 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(1023.3333333333335 634.5202020202021) rotate(0 54.545454545454504 50)"><path d="M25 0 C38.24 -0.34, 52.52 -0.4, 84.09 0 M25 0 C43.22 -0.14, 60.61 -0.07, 84.09 0 M84.09 0 C99.74 -0.15, 109.55 6.65, 109.09 25 M84.09 0 C101.51 1.87, 110.05 8.18, 109.09 25 M109.09 25 C111.11 39.03, 107.98 57.73, 109.09 75 M109.09 25 C108.98 44.18, 109.07 62.82, 109.09 75 M109.09 75 C107.94 92.54, 102.02 101.39, 84.09 100 M109.09 75 C110.7 92.61, 103 99.39, 84.09 100 M84.09 100 C71.63 101.14, 57.62 98.14, 25 100 M84.09 100 C70.64 99.85, 58.84 100.65, 25 100 M25 100 C6.4 99.65, 1.6 93.59, 0 75 M25 100 C6.74 101.89, -2.03 93.21, 0 75 M0 75 C-0.09 58.47, 0.35 46.96, 0 25 M0 75 C-0.44 56.37, 0.39 39.04, 0 25 M0 25 C1.64 6.41, 7.17 1.87, 25 0 M0 25 C-0.39 7.74, 6.9 1.81, 25 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(1222.4242424242425 672.7020202020203) rotate(0 -43.18181818181813 0.45454545454543904)"><path d="M-0.83 0.99 C-15.56 1.08, -73.16 1.91, -87.42 1.72 M0.94 0.46 C-13.52 0.72, -70.58 0, -85.27 0.02" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1222.4242424242425 672.7020202020203) rotate(0 -43.18181818181813 0.45454545454543904)"><path d="M-61.72 -8.39 C-68.95 -7.12, -78.2 -2.25, -85.27 0.02 M-61.72 -8.39 C-67.58 -6.74, -70.89 -4.31, -85.27 0.02" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1222.4242424242425 672.7020202020203) rotate(0 -43.18181818181813 0.45454545454543904)"><path d="M-61.83 8.71 C-69.18 3.48, -78.39 1.85, -85.27 0.02 M-61.83 8.71 C-67.58 6.77, -70.87 5.62, -85.27 0.02" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1226.9696969696972 658.1565656565658) rotate(0 125.56987762451172 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">TileButton.cpp (QButton)</text></g><g transform="translate(1318.8888888888887 918.6111111111111) rotate(0 53.07018280029297 17.5)"><text x="0" y="24.668" font-family="Virgil, Segoe UI Emoji" font-size="28px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">main.cpp</text></g><g transform="translate(1284.4444444444448 785.8333333333335) rotate(0 139.84982299804688 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">SpriteProvider.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(stores all QPixmap Sprites)</text></g><g stroke-linecap="round"><g transform="translate(1268.888888888889 792.5000000000001) rotate(0 -78.8888888888888 -39.44444444444446)"><path d="M-0.72 1.11 C-27.09 -11.74, -131.06 -65.01, -157.21 -78.23 M1.11 0.65 C-25.46 -12.45, -131.29 -66.53, -157.86 -80.01" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1268.888888888889 792.5000000000001) rotate(0 -78.8888888888888 -39.44444444444446)"><path d="M-133.05 -76.97 C-140.74 -77.35, -151.08 -79.2, -157.86 -80.01 M-133.05 -76.97 C-142.62 -78.36, -149.77 -80.05, -157.86 -80.01" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1268.888888888889 792.5000000000001) rotate(0 -78.8888888888888 -39.44444444444446)"><path d="M-140.81 -61.73 C-145.36 -67.94, -152.71 -75.68, -157.86 -80.01 M-140.81 -61.73 C-147.57 -68.47, -151.97 -75.57, -157.86 -80.01" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1183.3333333333335 726.9444444444446) rotate(0 112.28987121582031 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">QPixmap get_sprite(id)</text></g><g transform="translate(933.3333333333333 818.0555555555557) rotate(0 112.28987121582031 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">QPixmap get_sprite(id)</text></g><g stroke-linecap="round"><g transform="translate(1272.2222222222224 836.784364824992) rotate(0 -393.33333333333337 -97.142182412496)"><path d="M0.45 0.38 C-130.53 -32.13, -655.33 -161.77, -786.53 -194.17 M-0.77 -0.46 C-131.85 -32.84, -656.28 -160.56, -787.41 -192.57" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1272.2222222222224 836.784364824992) rotate(0 -393.33333333333337 -97.142182412496)"><path d="M-762.56 -195.31 C-768.09 -194.31, -774.72 -193.98, -787.41 -192.57 M-762.56 -195.31 C-769.74 -193.76, -777.78 -192.73, -787.41 -192.57" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1272.2222222222224 836.784364824992) rotate(0 -393.33333333333337 -97.142182412496)"><path d="M-766.62 -178.69 C-771.26 -181.85, -776.88 -185.66, -787.41 -192.57 M-766.62 -178.69 C-772.53 -182.55, -779.25 -186.94, -787.41 -192.57" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(1034.4444444444446 784.7222222222223) rotate(0 1.6666666666667425 15.555555555555543)"><path d="M0.18 0.32 C0.72 5.52, 2.69 26.35, 3.2 31.54 M-0.38 0.01 C0.08 5.03, 2.16 25.7, 2.7 30.79" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(1351.1111111111113 908.0555555555557) rotate(0 10.201238247079914 -28.333333333333258)"><path d="M-0.46 0.92 C2.78 -8.25, 16.75 -46.17, 20.2 -55.79 M1.5 0.36 C4.49 -9.08, 16.16 -48.13, 19.14 -57.45" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1351.1111111111113 908.0555555555557) rotate(0 10.201238247079914 -28.333333333333258)"><path d="M20.4 -32.48 C21.63 -41.95, 21.1 -51, 19.14 -57.45 M20.4 -32.48 C20.49 -39.78, 19.35 -46.28, 19.14 -57.45" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1351.1111111111113 908.0555555555557) rotate(0 10.201238247079914 -28.333333333333258)"><path d="M4.06 -37.51 C11.24 -45.08, 16.68 -52.29, 19.14 -57.45 M4.06 -37.51 C8.96 -43.4, 12.59 -48.42, 19.14 -57.45" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1361.1111111111109 878.1000000000004) rotate(0 158.83984375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">initialize (load hdf5 spritesheet)</text></g><g stroke-linecap="round"><g transform="translate(1305.5555555555557 936.9444444444446) rotate(0 -63.33333333333337 -0.5555555555555429)"><path d="M-0.43 0.11 C-21.48 -0.3, -105.83 -1.88, -126.74 -2.19 M1.55 -0.87 C-19.63 -1.19, -106.43 -1.24, -127.72 -1.22" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1305.5555555555557 936.9444444444446) rotate(0 -63.33333333333337 -0.5555555555555429)"><path d="M-104.23 -9.77 C-110.24 -7.71, -118.44 -3.97, -127.72 -1.22 M-104.23 -9.77 C-109.28 -8.07, -116.44 -5.49, -127.72 -1.22" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1305.5555555555557 936.9444444444446) rotate(0 -63.33333333333337 -0.5555555555555429)"><path d="M-104.23 7.33 C-110.28 4.87, -118.48 4.08, -127.72 -1.22 M-104.23 7.33 C-109.11 4.8, -116.27 3.14, -127.72 -1.22" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1203.3333333333335 930.2777777777778) rotate(0 55.729949951171875 25)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">construct</text><text x="0" y="42.62" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">MainWindow</text></g><g transform="translate(542.2222222222224 121.38888888888903) rotate(0 113.79843139648438 17.5)"><text x="0" y="24.668" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="28px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">EventHandler.cpp</text></g><g transform="translate(511.1111111111113 154.16666666666674) rotate(0 155.94985961914062 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#f08c00" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onLevelNameUpdated(new_name)</text></g><g transform="translate(834.4444444444443 1134.1666666666667) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#f08c00" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(560 378.61111111111126) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#f08c00" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(835.5555555555554 1156.388888888889) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(835.5555555555554 1179.7222222222222) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#2f9e44" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(835.5555555555554 1199.7222222222222) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(508.88888888888914 182.5000000000001) rotate(0 164.08982849121094 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#2f9e44" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onLevelWriteRequested(file_path)</text></g><g transform="translate(564.4444444444448 209.16666666666686) rotate(0 102.21990203857422 37.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onTileEntered(index)</text><text x="0" y="42.62" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onTileExited(index)</text><text x="0" y="67.62" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onTileClicked(index)</text></g><g stroke-linecap="round" transform="translate(467.77777777777806 95.83333333333348) rotate(0 190 127.2222222222222)"><path d="M32 0 C99.31 1.79, 168.77 1.21, 348 0 M32 0 C134.98 1.12, 238.33 0.36, 348 0 M348 0 C368.49 1.03, 378.15 12.6, 380 32 M348 0 C367.35 0.61, 377.88 9.94, 380 32 M380 32 C380.1 84.74, 379.31 141.3, 380 222.44 M380 32 C379.97 96.79, 379.78 163.12, 380 222.44 M380 222.44 C379.4 245.48, 370.62 255.32, 348 254.44 M380 222.44 C380.23 242.57, 371.38 252.49, 348 254.44 M348 254.44 C272.94 254.7, 197.6 254.59, 32 254.44 M348 254.44 C245.83 254.63, 142.8 255.15, 32 254.44 M32 254.44 C10.8 252.83, -1.78 243.8, 0 222.44 M32 254.44 C12.95 253.63, 0.02 245.45, 0 222.44 M0 222.44 C-2.03 149.77, -3.34 73.88, 0 32 M0 222.44 C-0.58 178.42, 0.62 131.73, 0 32 M0 32 C-1.19 9.19, 11.9 -1.93, 32 0 M0 32 C0.07 9.73, 11.54 -1.03, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(544.4444444444446 281.38888888888897) rotate(0 118.32988739013672 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onNewTileIdSelected(id)</text></g><g transform="translate(572.2222222222222 305.83333333333354) rotate(0 83.0199203491211 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onZoomed(delta)</text></g><g transform="translate(186.66666666666674 321.38888888888897) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#f08c00" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(1274.4444444444446 680.2777777777778) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(10 552.5000000000001) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(1306.6666666666665 499.16666666666674) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#2f9e44" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(786.6666666666665 381.38888888888897) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(1048.8888888888887 418.05555555555566) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(462.2222222222224 1178.0555555555557) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(962.2222222222224 342.50000000000017) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(532.2222222222224 55.83333333333326) rotate(0 133.99624633789062 20)"><text x="0" y="14.096" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">connects emitters and overwriters</text><text x="0" y="34.096000000000004" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">makes interaction possible</text></g><g transform="translate(20.000000000000114 191.38888888888897) rotate(0 224.7923583984375 40)"><text x="0" y="14.096" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Legende:</text><text x="0" y="34.096000000000004" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits] -> dispatches event handler event method</text><text x="0" y="54.096000000000004" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites] -> inherits from EventHandler and</text><text x="0" y="74.096" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic"> overwrites event method</text></g><g transform="translate(40.00000000000023 10) rotate(0 184.9500732421875 67.5)"><text x="0" y="31.716" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Formless </text><text x="0" y="76.71600000000001" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">System Architecture </text><text x="0" y="121.71600000000001" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Diagramm</text></g></svg> \ No newline at end of file + @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }</style></defs><rect x="0" y="0" width="1688.7907986111109" height="1234.7222222222222" fill="#ffffff"></rect><g stroke-linecap="round" transform="translate(181.33333333333303 468.429292929293) rotate(0 496.5 313.5)"><path d="M32 0 C392.22 -1.22, 750.78 -1.96, 961 0 M32 0 C350.37 -2.95, 668.6 -2.73, 961 0 M961 0 C981.11 -0.8, 992.43 10.61, 993 32 M961 0 C982.35 -1.02, 994.77 10.24, 993 32 M993 32 C990.27 180.3, 990.44 329.77, 993 595 M993 32 C993.61 250.68, 993.46 469.57, 993 595 M993 595 C994.01 615.74, 983.64 626.88, 961 627 M993 595 C994.03 614.05, 981.9 627.65, 961 627 M961 627 C646.22 628.26, 332.93 627.51, 32 627 M961 627 C711.11 624.58, 460.9 624.42, 32 627 M32 627 C10.59 626.53, 0.77 616.89, 0 595 M32 627 C9.28 624.92, -0.3 617.43, 0 595 M0 595 C0.03 426.99, -0.11 258.91, 0 32 M0 595 C-1.21 479.68, -1.88 365.05, 0 32 M0 32 C1.86 10.09, 9.1 -1, 32 0 M0 32 C0.31 11.97, 10.76 0.02, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(519.9999999999998 397.3181818181819) rotate(0 98.72837829589844 35)"><text x="0" y="24.668" font-family="Virgil, Segoe UI Emoji" font-size="28px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">MainWindow.cpp</text><text x="0" y="59.668" font-family="Virgil, Segoe UI Emoji" font-size="28px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QMainWindow)</text></g><g stroke-linecap="round"><g transform="translate(180.33333333333303 529.4292929292931) rotate(0 497 -1)"><path d="M-0.62 0.95 C165.13 0.91, 827.6 -0.38, 993.57 -0.8 M1.25 0.4 C166.89 0.12, 826.77 -1.62, 992.4 -2.3" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(602.7777777777776 480.429292929293) rotate(0 55.43994903564453 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">TopBar.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QToolBar)</text></g><g stroke-linecap="round" transform="translate(210.33333333333303 482.429292929293) rotate(0 117 17)"><path d="M8.5 0 C82.95 -0.86, 159.8 -1.13, 225.5 0 M8.5 0 C71.09 -0.8, 134.25 -1.35, 225.5 0 M225.5 0 C232.33 0.33, 232.7 2.76, 234 8.5 M225.5 0 C233.15 -1.94, 232.78 3.56, 234 8.5 M234 8.5 C234.21 14.51, 234.75 16.2, 234 25.5 M234 8.5 C234.01 14.79, 233.84 21.05, 234 25.5 M234 25.5 C234.43 31.84, 231.54 35.7, 225.5 34 M234 25.5 C235.6 32.53, 230.89 33.21, 225.5 34 M225.5 34 C143.1 32.42, 65.1 32.35, 8.5 34 M225.5 34 C151.33 35.67, 76.52 36.47, 8.5 34 M8.5 34 C1.77 32.02, 1.93 31.63, 0 25.5 M8.5 34 C3.25 34.52, 1.32 30.23, 0 25.5 M0 25.5 C0.55 19.94, -1 13.59, 0 8.5 M0 25.5 C-0.13 21.51, -0.72 16.51, 0 8.5 M0 8.5 C1.94 3.8, 4.48 -0.8, 8.5 0 M0 8.5 C1.85 3.76, 3.37 -0.05, 8.5 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(217.33333333333303 491.429292929293) rotate(0 0.5 10)"><path d="M0.25 0 C0.42 0.01, 0.61 -0.02, 0.75 0 M0.25 0 C0.35 0, 0.45 0.01, 0.75 0 M0.75 0 C0.89 -0.04, 0.36 0.81, 1 0.25 M0.75 0 C1.55 0.25, 1.22 -0.63, 1 0.25 M1 0.25 C1 7.43, 1.16 12.83, 1 19.75 M1 0.25 C1.04 6.11, 1.06 12.31, 1 19.75 M1 19.75 C1.88 18.99, 0.8 19.82, 0.75 20 M1 19.75 C1.15 20.78, 1.32 19.55, 0.75 20 M0.75 20 C0.64 20.01, 0.47 20, 0.25 20 M0.75 20 C0.64 19.99, 0.54 20.01, 0.25 20 M0.25 20 C-0.51 19.6, 0.64 20.51, 0 19.75 M0.25 20 C0.6 21.07, 0.74 19.62, 0 19.75 M0 19.75 C-0.27 15.59, 0.89 10.28, 0 0.25 M0 19.75 C-0.15 15.03, 0.3 11.21, 0 0.25 M0 0.25 C0.96 -0.63, 0.37 0.04, 0.25 0 M0 0.25 C-1.04 -0.02, 0.34 1.02, 0.25 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(229.33333333333303 372.429292929293) rotate(0 -1 53.5)"><path d="M-0.81 -1.05 C-1.22 16.8, -1.36 89.29, -1.4 107.47 M0.96 1.01 C0.36 18.47, -1.65 88.06, -2.03 105.59" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(229.33333333333303 372.429292929293) rotate(0 -1 53.5)"><path d="M-9.97 81.88 C-8.59 92.11, -2.98 101.84, -2.03 105.59 M-9.97 81.88 C-6.47 90.15, -4.54 100.94, -2.03 105.59" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(229.33333333333303 372.429292929293) rotate(0 -1 53.5)"><path d="M7.13 82.33 C1.89 92.27, 0.88 101.83, -2.03 105.59 M7.13 82.33 C4.08 90.57, -0.53 101.19, -2.03 105.59" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(149.33333333333303 347.429292929293) rotate(0 87.659912109375 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">LevelNameEdit.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QLineEdit)</text></g><g stroke-linecap="round" transform="translate(1063.333333333333 486.429292929293) rotate(0 47.5 12)"><path d="M6 0 C34.28 0.89, 60.18 0.43, 89 0 M6 0 C25.62 0.6, 43.35 0.53, 89 0 M89 0 C94.69 0.9, 93.44 1.88, 95 6 M89 0 C92.78 0.44, 96.27 1.45, 95 6 M95 6 C93.88 9.47, 95.27 10.92, 95 18 M95 6 C95.28 9.11, 95.1 13.08, 95 18 M95 18 C94.21 21.66, 93.22 22.3, 89 24 M95 18 C96.62 23.93, 91.93 23.49, 89 24 M89 24 C56.56 26.15, 25.69 22.71, 6 24 M89 24 C58.42 24.22, 27.9 24.91, 6 24 M6 24 C1.19 22.28, 1.69 21.82, 0 18 M6 24 C2.56 23.95, 2.28 23.17, 0 18 M0 18 C-0.32 13.43, 1.18 8.69, 0 6 M0 18 C-0.43 13.94, 0.08 10.5, 0 6 M0 6 C-1.16 0.67, 0.99 1.82, 6 0 M0 6 C2.11 3.57, 0.77 -2.16, 6 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1085.333333333333 488.429292929293) rotate(0 23.97998046875 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Save</text></g><g stroke-linecap="round"><g transform="translate(1242.333333333333 488.429292929293) rotate(0 -40.5 2)"><path d="M0.21 0.91 C-13.54 1.66, -68.62 4.36, -81.99 4.83 M-1.14 0.34 C-14.57 0.73, -66.61 2.39, -79.79 3.15" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1242.333333333333 488.429292929293) rotate(0 -40.5 2)"><path d="M-56.69 -6.4 C-63.1 -4.72, -71.17 1.88, -79.79 3.15 M-56.69 -6.4 C-63.31 -3.12, -69.07 -0.07, -79.79 3.15" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1242.333333333333 488.429292929293) rotate(0 -40.5 2)"><path d="M-55.96 10.69 C-62.66 6.49, -70.99 7.21, -79.79 3.15 M-55.96 10.69 C-62.69 9.23, -68.65 7.53, -79.79 3.15" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1247.333333333333 477.429292929293) rotate(0 129.68988037109375 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">SaveButton.cpp (QButton)</text></g><g stroke-linecap="round" transform="translate(1005.333333333333 484.429292929293) rotate(0 13.5 17.5)"><path d="M6.75 0 C9.92 -0.2, 16.31 1.38, 20.25 0 M6.75 0 C11.62 -0.38, 16.32 -0.58, 20.25 0 M20.25 0 C26.35 -1.97, 28.5 1.66, 27 6.75 M20.25 0 C24.01 -1.02, 27.24 2.84, 27 6.75 M27 6.75 C28.85 14.28, 28.08 22.09, 27 28.25 M27 6.75 C26.92 14.38, 27.65 22.43, 27 28.25 M27 28.25 C26.26 31.42, 22.96 35.3, 20.25 35 M27 28.25 C29.18 33.03, 25.2 33.24, 20.25 35 M20.25 35 C15.67 35.81, 12.98 35.93, 6.75 35 M20.25 35 C16.03 34.72, 10.87 34.5, 6.75 35 M6.75 35 C2.9 34.03, -0.39 33.16, 0 28.25 M6.75 35 C0.73 33.52, -2.27 30.99, 0 28.25 M0 28.25 C1.12 23.57, 1.49 15.7, 0 6.75 M0 28.25 C0.53 21.91, 0.3 15.73, 0 6.75 M0 6.75 C0.21 2.02, 1.34 -0.13, 6.75 0 M0 6.75 C-0.3 1.59, 1.63 1.72, 6.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1012.333333333333 489.429292929293) rotate(0 6.5 12.5)"><text x="6.5" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">+</text></g><g stroke-linecap="round" transform="translate(912.333333333333 484.429292929293) rotate(0 40.5 17.5)"><path d="M8.75 0 C22.56 0.4, 37.31 -1.91, 72.25 0 M8.75 0 C23.05 -1.57, 38.12 0.11, 72.25 0 M72.25 0 C79.86 -0.3, 79.84 2.62, 81 8.75 M72.25 0 C78.7 -1.52, 83.27 4.93, 81 8.75 M81 8.75 C80.09 13.85, 80.67 21.49, 81 26.25 M81 8.75 C81.41 11.99, 80.31 16.06, 81 26.25 M81 26.25 C80.07 33.14, 79.58 34.9, 72.25 35 M81 26.25 C80.75 30.39, 78.08 34.73, 72.25 35 M72.25 35 C51.55 36.58, 32.98 33.29, 8.75 35 M72.25 35 C48.97 35.89, 24.15 35.79, 8.75 35 M8.75 35 C4.36 35.12, -0.4 31.08, 0 26.25 M8.75 35 C3.76 33.6, 1.1 34.33, 0 26.25 M0 26.25 C-1.35 23.1, 1.08 17.8, 0 8.75 M0 26.25 C0.84 21.29, 0.31 17.23, 0 8.75 M0 8.75 C-1.1 1.96, 3.44 -0.83, 8.75 0 M0 8.75 C-0.18 4.03, 2.99 -1.76, 8.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(926.8633397420244 489.429292929293) rotate(0 25.969993591308594 12.5)"><text x="25.969993591308594" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">100%</text></g><g stroke-linecap="round" transform="translate(872.333333333333 483.429292929293) rotate(0 14.5 17.5)"><path d="M7.25 0 C10.22 0.81, 16.13 0.62, 21.75 0 M7.25 0 C10.45 0.04, 13.83 -0.2, 21.75 0 M21.75 0 C28.53 -1.66, 30.01 3.94, 29 7.25 M21.75 0 C25.25 -2.12, 27.32 2.65, 29 7.25 M29 7.25 C27.46 15.36, 29.95 22.12, 29 27.75 M29 7.25 C29.49 11.1, 29 15.36, 29 27.75 M29 27.75 C30.06 31.65, 24.8 35.36, 21.75 35 M29 27.75 C30.26 30.8, 26.27 32.76, 21.75 35 M21.75 35 C15.99 33.78, 11.09 33.83, 7.25 35 M21.75 35 C15.58 34.65, 9.83 34.46, 7.25 35 M7.25 35 C3.59 36.96, -1.4 33.4, 0 27.75 M7.25 35 C4.66 34.8, 1.38 33.03, 0 27.75 M0 27.75 C-1.77 20.42, 0.62 11.76, 0 7.25 M0 27.75 C-0.43 21.36, -0.19 15.55, 0 7.25 M0 7.25 C0.64 1.25, 0.77 1.31, 7.25 0 M0 7.25 C1.24 3.09, 4.53 0.82, 7.25 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(882.723340352376 488.429292929293) rotate(0 4.109992980957031 12.5)"><text x="4.109992980957031" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">-</text></g><g stroke-linecap="round"><g transform="translate(1025.333333333333 418.429292929293) rotate(0 0.5 33.5)"><path d="M-0.62 -0.01 C-0.55 11.31, 0.02 56.24, 0.23 67.4 M1.26 -1.07 C1.73 9.93, 2.79 53.94, 2.54 65.49" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1025.333333333333 418.429292929293) rotate(0 0.5 33.5)"><path d="M-6.11 42.04 C-3.77 47.5, -0.6 54.94, 2.54 65.49 M-6.11 42.04 C-2.46 49.71, -1.44 56.21, 2.54 65.49" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1025.333333333333 418.429292929293) rotate(0 0.5 33.5)"><path d="M10.99 41.96 C8.45 47.36, 6.73 54.82, 2.54 65.49 M10.99 41.96 C9.59 49.67, 5.56 56.2, 2.54 65.49" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(948.333333333333 390.429292929293) rotate(0 -1.5 45)"><path d="M0.31 -0.19 C-0.53 14.85, -3.52 75.53, -3.92 90.75 M-0.99 -1.34 C-1.55 13.32, -1.46 73.9, -1.7 89.03" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(948.333333333333 390.429292929293) rotate(0 -1.5 45)"><path d="M-10.09 65.48 C-7.04 73.14, -2.17 85.36, -1.7 89.03 M-10.09 65.48 C-5.72 74.54, -2.43 83.73, -1.7 89.03" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(948.333333333333 390.429292929293) rotate(0 -1.5 45)"><path d="M7.01 65.59 C3.37 73.25, 1.54 85.43, -1.7 89.03 M7.01 65.59 C4.61 74.74, 1.14 83.9, -1.7 89.03" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(857.333333333333 427.429292929293) rotate(0 12.5 27)"><path d="M-0.25 -0.42 C3.93 8.8, 21.72 45.57, 25.74 54.77 M1.81 -1.68 C5.85 7.24, 21.12 43.96, 25.18 53.04" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(857.333333333333 427.429292929293) rotate(0 12.5 27)"><path d="M8.05 34.83 C13.31 42.52, 21.32 45.8, 25.18 53.04 M8.05 34.83 C13.65 41.12, 20.02 48.33, 25.18 53.04" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(857.333333333333 427.429292929293) rotate(0 12.5 27)"><path d="M23.77 28.08 C23.46 38.12, 25.93 43.77, 25.18 53.04 M23.77 28.08 C23.58 36.73, 24.22 46.39, 25.18 53.04" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(975.333333333333 397.429292929293) rotate(0 142.2398681640625 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ZoomInButton.cpp (QButton)</text></g><g transform="translate(919.333333333333 368.429292929293) rotate(0 154.099853515625 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ZoomInfoBUtton.cpp (QButton)</text></g><g transform="translate(739.333333333333 400.429292929293) rotate(0 98.07991027832031 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">ZoomOutBUtton.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic"> (QButton)</text></g><g stroke-linecap="round" transform="translate(908.333333333333 528.4292929292931) rotate(0 132.5 282.5)"><path d="M32 0 C107.68 -0.2, 181.93 -0.74, 233 0 M32 0 C84.58 -0.32, 139.55 0.62, 233 0 M233 0 C254.72 0.92, 264.11 9.95, 265 32 M233 0 C252.46 0, 264.98 12.59, 265 32 M265 32 C263.46 146.81, 263.79 261.73, 265 533 M265 32 C264.71 216.17, 264.44 399.83, 265 533 M265 533 C264.79 556.25, 253.75 564.54, 233 565 M265 533 C263.43 553.47, 254.63 565.31, 233 565 M233 565 C181.87 565.95, 131.39 567.04, 32 565 M233 565 C163.75 564.45, 93.71 565.49, 32 565 M32 565 C11.87 566.97, 1.46 553.94, 0 533 M32 565 C11.74 566.93, 0.6 554.32, 0 533 M0 533 C0.22 423.53, -0.28 314.91, 0 32 M0 533 C0.18 386.7, 0.13 240.44, 0 32 M0 32 C1.34 10.17, 11.54 1.36, 32 0 M0 32 C1.77 12.9, 12.25 -0.5, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(1223.333333333333 582.4292929292931) rotate(0 -23 -1.4999999999999858)"><path d="M-0.37 -0.23 C-8.08 -0.87, -38.83 -2.82, -46.38 -3.35 M0.44 -0.83 C-7.08 -1.44, -37.63 -2.46, -45.34 -2.83" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1223.333333333333 582.4292929292931) rotate(0 -23 -1.4999999999999858)"><path d="M-23.38 -9.83 C-29.77 -8.69, -35.99 -5.47, -45.34 -2.83 M-23.38 -9.83 C-28.55 -8.18, -32.93 -6.81, -45.34 -2.83" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1223.333333333333 582.4292929292931) rotate(0 -23 -1.4999999999999858)"><path d="M-24.02 5.92 C-30.3 2.77, -36.34 1.69, -45.34 -2.83 M-24.02 5.92 C-29.02 4.08, -33.27 1.95, -45.34 -2.83" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1225.333333333333 568.4292929292931) rotate(0 77.17992401123047 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">TileSelector.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QScrollArea)</text></g><g stroke-linecap="round" transform="translate(180.33333333333303 533.4292929292931) rotate(0 363 279.5)"><path d="M32 0 C215.92 1.83, 398.86 2.46, 694 0 M32 0 C180.91 0.52, 329.24 0.39, 694 0 M694 0 C714.71 1.49, 727.21 9.49, 726 32 M694 0 C713.4 -1.3, 728.05 11.18, 726 32 M726 32 C723.76 180.22, 724.95 328.51, 726 527 M726 32 C725.6 187.45, 725.35 343.49, 726 527 M726 527 C727.77 546.98, 713.79 560.64, 694 559 M726 527 C724.33 547.44, 716.28 559.42, 694 559 M694 559 C523.33 555.73, 351.72 556.14, 32 559 M694 559 C519.52 556.36, 345.02 556.09, 32 559 M32 559 C8.95 560.86, 1.46 549.67, 0 527 M32 559 C8.93 559.29, 2.04 546.92, 0 527 M0 527 C-1.75 411.71, -0.93 296.78, 0 32 M0 527 C-1.1 389.49, -1.21 251.32, 0 32 M0 32 C-0.11 9.35, 9.88 0.55, 32 0 M0 32 C0.53 12.21, 12.51 -0.56, 32 0" stroke="#e03131" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(512.333333333333 1130.429292929293) rotate(0 0 -16.5)"><path d="M-0.52 -0.22 C-0.41 -5.75, 0.34 -27.1, 0.47 -32.65 M0.22 -0.81 C0.31 -6.27, 0.31 -28.04, 0.28 -33.44" stroke="#e03131" stroke-width="1" fill="none"></path></g><g transform="translate(512.333333333333 1130.429292929293) rotate(0 0 -16.5)"><path d="M5.96 -17.94 C4.03 -21.41, 3.36 -25.88, 0.28 -33.44 M5.96 -17.94 C4.57 -20.88, 3.41 -24.45, 0.28 -33.44" stroke="#e03131" stroke-width="1" fill="none"></path></g><g transform="translate(512.333333333333 1130.429292929293) rotate(0 0 -16.5)"><path d="M-5.33 -17.92 C-4.24 -21.34, -1.87 -25.81, 0.28 -33.44 M-5.33 -17.92 C-4.39 -20.85, -3.22 -24.43, 0.28 -33.44" stroke="#e03131" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(454.33333333333303 1133.429292929293) rotate(0 74.98992156982422 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">LevelView.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QGraphicsView)</text></g><g stroke-linecap="round" transform="translate(315.33333333333303 578.4292929292931) rotate(0 241 228.5)"><path d="M32 0 C146.33 -1.42, 257.76 -0.74, 450 0 M32 0 C115.45 1.81, 200.12 1.28, 450 0 M450 0 C471.46 -0.74, 482.45 8.99, 482 32 M450 0 C471.62 -1.64, 480.4 12.52, 482 32 M482 32 C480.83 137.55, 482.65 241.93, 482 425 M482 32 C481.31 143.38, 481.08 253.68, 482 425 M482 425 C483.61 444.62, 472.21 457.89, 450 457 M482 425 C483.83 445.93, 470.94 456.08, 450 457 M450 457 C293.51 457.25, 135.32 457.52, 32 457 M450 457 C297.48 456.29, 143.84 456.54, 32 457 M32 457 C11.7 455.78, 1 448.29, 0 425 M32 457 C9.59 455.68, 2.19 444.24, 0 425 M0 425 C0.5 336.06, 0.98 247.97, 0 32 M0 425 C-0.88 281.81, -0.96 139.85, 0 32 M0 32 C1.23 12.56, 12.45 -0.4, 32 0 M0 32 C-1.03 11.67, 9 1.82, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(738.333333333333 1131.429292929293) rotate(0 -1 -48)"><path d="M-1.1 -1.19 C-1.57 -17.1, -1.85 -80.14, -2.02 -95.86 M0.52 0.8 C-0.18 -14.85, -2.4 -77.84, -2.98 -94.24" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(738.333333333333 1131.429292929293) rotate(0 -1 -48)"><path d="M6.4 -71.07 C1.06 -79.68, -0.15 -88.38, -2.98 -94.24 M6.4 -71.07 C3.17 -78.61, 0.8 -86.65, -2.98 -94.24" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(738.333333333333 1131.429292929293) rotate(0 -1 -48)"><path d="M-10.69 -70.46 C-9.77 -79.14, -4.72 -88.06, -2.98 -94.24 M-10.69 -70.46 C-8.09 -78.14, -4.63 -86.39, -2.98 -94.24" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(669.333333333333 1135.429292929293) rotate(0 82.77991485595703 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">LevelScene.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QGraphicsScene)</text></g><g stroke-linecap="round" transform="translate(320.33333333333303 588.4292929292931) rotate(0 21.5 18.5)"><path d="M9.25 0 C20.01 0.76, 26 0.03, 33.75 0 M9.25 0 C19.41 -0.24, 28.62 0.61, 33.75 0 M33.75 0 C40.46 1.11, 42.64 3.02, 43 9.25 M33.75 0 C37.82 1.09, 45.27 3.31, 43 9.25 M43 9.25 C43.43 14.75, 41.78 17.92, 43 27.75 M43 9.25 C42.23 14.12, 42.47 17.97, 43 27.75 M43 27.75 C42.57 33.29, 38.49 35.69, 33.75 37 M43 27.75 C42.31 36, 39.42 35.78, 33.75 37 M33.75 37 C27.37 37.9, 18.55 36.99, 9.25 37 M33.75 37 C27.4 37.24, 20.28 36.69, 9.25 37 M9.25 37 C3.16 35.98, -0.62 34.77, 0 27.75 M9.25 37 C4.45 38.28, 0.77 35.29, 0 27.75 M0 27.75 C-0.84 21.83, -1.11 18.45, 0 9.25 M0 27.75 C-0.9 22.6, -0.63 17.73, 0 9.25 M0 9.25 C1.28 2.3, 2.36 0.79, 9.25 0 M0 9.25 C-2.17 0.79, 1.37 -1.65, 9.25 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(366.33333333333303 590.4292929292931) rotate(0 19.5 17.5)"><path d="M8.75 0 C14.48 0.81, 22.09 1.13, 30.25 0 M8.75 0 C12.41 -0.36, 17.27 -0.4, 30.25 0 M30.25 0 C34.66 -1.31, 38.4 4.72, 39 8.75 M30.25 0 C35.58 -1.22, 38.69 2.57, 39 8.75 M39 8.75 C38.03 13.32, 38.56 17.7, 39 26.25 M39 8.75 C38.91 14.66, 39.09 20.93, 39 26.25 M39 26.25 C38.38 32.93, 37.27 36.11, 30.25 35 M39 26.25 C39.77 33.46, 35.99 33.98, 30.25 35 M30.25 35 C20.98 36.73, 13.64 35.46, 8.75 35 M30.25 35 C22.23 34.84, 16.11 34.56, 8.75 35 M8.75 35 C2.19 35.79, -1.89 30.09, 0 26.25 M8.75 35 C1.2 33.35, 2.23 34.3, 0 26.25 M0 26.25 C1.13 21.77, 0.87 18.25, 0 8.75 M0 26.25 C0.17 20.64, 0.41 15.47, 0 8.75 M0 8.75 C0.37 1, 0.95 -0.63, 8.75 0 M0 8.75 C-2.27 1.68, 4.22 0.85, 8.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(407.33333333333303 592.4292929292931) rotate(0 19 17.5)"><path d="M8.75 0 C12.21 -2.07, 17.95 -1.52, 29.25 0 M8.75 0 C16.34 -0.65, 25.62 -0.32, 29.25 0 M29.25 0 C35.97 -0.96, 38.17 2.3, 38 8.75 M29.25 0 C33.65 0.31, 37.44 3.84, 38 8.75 M38 8.75 C36.31 13.46, 36.3 18.34, 38 26.25 M38 8.75 C37.77 15.63, 37.75 20.41, 38 26.25 M38 26.25 C38.81 33.71, 34.44 36.29, 29.25 35 M38 26.25 C36.95 33.87, 35.7 34.47, 29.25 35 M29.25 35 C23.99 34.96, 19.58 35.62, 8.75 35 M29.25 35 C21.64 35.48, 13.28 35.95, 8.75 35 M8.75 35 C3.6 36.06, -0.03 32.15, 0 26.25 M8.75 35 C5.01 36.72, 1.66 32.54, 0 26.25 M0 26.25 C-0.4 20.69, -0.62 14.43, 0 8.75 M0 26.25 C0.97 20.51, -0.01 14.56, 0 8.75 M0 8.75 C-1.06 2.61, 1.97 -0.09, 8.75 0 M0 8.75 C0.27 2.26, 2.31 1.34, 8.75 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(443.33333333333303 593.4292929292931) rotate(0 23.5 17)"><path d="M8.5 0 C17.98 -0.54, 28.48 -0.79, 38.5 0 M8.5 0 C19.1 1.21, 28.52 0.08, 38.5 0 M38.5 0 C42.26 -1.06, 46.69 1.89, 47 8.5 M38.5 0 C44.07 0.27, 46.34 2.23, 47 8.5 M47 8.5 C46.21 15.46, 47.84 21.78, 47 25.5 M47 8.5 C47.86 14.93, 46.52 21.43, 47 25.5 M47 25.5 C45.53 32.33, 42.39 35.3, 38.5 34 M47 25.5 C46.76 33.3, 44.05 32.47, 38.5 34 M38.5 34 C26.79 33.78, 16.8 33.96, 8.5 34 M38.5 34 C27.54 33.62, 17.45 34.1, 8.5 34 M8.5 34 C2.5 34.19, -1.45 32.42, 0 25.5 M8.5 34 C0.87 34.71, -0.54 31.19, 0 25.5 M0 25.5 C-1.11 20.88, -0.96 15.77, 0 8.5 M0 25.5 C0.22 22.14, 0.65 18.26, 0 8.5 M0 8.5 C1.52 1.2, 3.35 -0.48, 8.5 0 M0 8.5 C0.5 1.77, 2.59 1.99, 8.5 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(90.33333333333303 598.4292929292931) rotate(0 114.5 3.5)"><path d="M-0.45 0.03 C37.84 1.39, 190.79 5.94, 229.13 7.13 M1.52 -1.01 C39.7 0.66, 190.32 7.14, 228.25 8.74" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(90.33333333333303 598.4292929292931) rotate(0 114.5 3.5)"><path d="M204.41 16.28 C210.51 14.68, 216.69 13.51, 228.25 8.74 M204.41 16.28 C211.84 13.8, 219.78 11.53, 228.25 8.74" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(90.33333333333303 598.4292929292931) rotate(0 114.5 3.5)"><path d="M205.14 -0.8 C210.91 1.89, 216.9 5.01, 228.25 8.74 M205.14 -0.8 C212.18 2.06, 219.89 5.13, 228.25 8.74" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(10.33333333333303 578.4292929292931) rotate(0 111.31987762451172 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Tile.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(QGraphicsPixmapItem)</text></g><g stroke-linecap="round" transform="translate(922.4242424242425 541.7929292929294) rotate(0 39.545454545454504 38.18181818181817)"><path d="M19.09 0 C31.99 0.05, 47.15 -0.53, 60 0 M19.09 0 C29.75 0.09, 39.48 -0.85, 60 0 M60 0 C70.78 -0.88, 78.34 7.86, 79.09 19.09 M60 0 C74.4 -2.27, 77.32 8.05, 79.09 19.09 M79.09 19.09 C80.58 28.26, 77.27 36.91, 79.09 57.27 M79.09 19.09 C79.94 28.61, 79.51 37.47, 79.09 57.27 M79.09 57.27 C79.29 69.54, 73.18 75.68, 60 76.36 M79.09 57.27 C77.93 70.21, 73.15 75.2, 60 76.36 M60 76.36 C48.22 76.64, 36.6 74.93, 19.09 76.36 M60 76.36 C45.42 76.38, 28.85 75.34, 19.09 76.36 M19.09 76.36 C5.78 75.7, 1.48 71.62, 0 57.27 M19.09 76.36 C7.67 76.59, 1.84 68.94, 0 57.27 M0 57.27 C1.15 50.14, 0.65 40.5, 0 19.09 M0 57.27 C0.89 49.78, -0.19 41.24, 0 19.09 M0 19.09 C1.96 5.63, 7.56 -1.36, 19.09 0 M0 19.09 C0.71 8.1, 6.47 0.09, 19.09 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(1014.2424242424242 544.5202020202021) rotate(0 44.09090909090912 39.09090909090909)"><path d="M19.55 0 C31.27 1.47, 41.22 -0.04, 68.64 0 M19.55 0 C30.45 0.13, 39.41 -0.6, 68.64 0 M68.64 0 C83.62 -0.73, 89.38 5.16, 88.18 19.55 M68.64 0 C82.38 1.74, 88.28 6.61, 88.18 19.55 M88.18 19.55 C88.44 29.55, 88.97 39.15, 88.18 58.64 M88.18 19.55 C88.86 30.86, 87.55 41.71, 88.18 58.64 M88.18 58.64 C86.87 73.14, 81.14 78.81, 68.64 78.18 M88.18 58.64 C90.11 71.8, 83.64 77.52, 68.64 78.18 M68.64 78.18 C50.29 76.91, 30.26 79.58, 19.55 78.18 M68.64 78.18 C58.95 78.16, 48.2 78.52, 19.55 78.18 M19.55 78.18 C6.42 77.91, -1.93 73.64, 0 58.64 M19.55 78.18 C5.16 76.73, 1.25 73.78, 0 58.64 M0 58.64 C-0.15 44.9, -1.77 29.35, 0 19.55 M0 58.64 C-0.53 47.68, -0.01 39.17, 0 19.55 M0 19.55 C0.14 6.1, 5.94 -0.56, 19.55 0 M0 19.55 C1.96 5.38, 6.93 1.77, 19.55 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(931.5151515151517 629.0656565656567) rotate(0 37.727272727272634 46.81818181818181)"><path d="M18.86 0 C28.49 -1.64, 41.56 1.46, 56.59 0 M18.86 0 C32.64 0.5, 45.79 -0.05, 56.59 0 M56.59 0 C68.38 1.18, 73.81 5.68, 75.45 18.86 M56.59 0 C67.39 0.5, 77.53 6.45, 75.45 18.86 M75.45 18.86 C77 33.49, 75.66 51.63, 75.45 74.77 M75.45 18.86 C75.63 37.14, 76.59 53.14, 75.45 74.77 M75.45 74.77 C75.74 89.12, 67.65 92, 56.59 93.64 M75.45 74.77 C74.97 87.93, 70.99 94.76, 56.59 93.64 M56.59 93.64 C46.03 93.4, 29.78 92.11, 18.86 93.64 M56.59 93.64 C43.36 94.39, 30.19 93.63, 18.86 93.64 M18.86 93.64 C4.94 93.41, 1.49 86.93, 0 74.77 M18.86 93.64 C7.83 93.32, -1.17 87.17, 0 74.77 M0 74.77 C2.1 57.55, 0.34 38.86, 0 18.86 M0 74.77 C-1.16 57.05, 0.43 41.23, 0 18.86 M0 18.86 C1.7 5.85, 5.21 0.68, 18.86 0 M0 18.86 C-1.03 6.63, 4.97 1, 18.86 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(1023.3333333333335 634.5202020202021) rotate(0 54.545454545454504 50)"><path d="M25 0 C38.24 -0.34, 52.52 -0.4, 84.09 0 M25 0 C43.22 -0.14, 60.61 -0.07, 84.09 0 M84.09 0 C99.74 -0.15, 109.55 6.65, 109.09 25 M84.09 0 C101.51 1.87, 110.05 8.18, 109.09 25 M109.09 25 C111.11 39.03, 107.98 57.73, 109.09 75 M109.09 25 C108.98 44.18, 109.07 62.82, 109.09 75 M109.09 75 C107.94 92.54, 102.02 101.39, 84.09 100 M109.09 75 C110.7 92.61, 103 99.39, 84.09 100 M84.09 100 C71.63 101.14, 57.62 98.14, 25 100 M84.09 100 C70.64 99.85, 58.84 100.65, 25 100 M25 100 C6.4 99.65, 1.6 93.59, 0 75 M25 100 C6.74 101.89, -2.03 93.21, 0 75 M0 75 C-0.09 58.47, 0.35 46.96, 0 25 M0 75 C-0.44 56.37, 0.39 39.04, 0 25 M0 25 C1.64 6.41, 7.17 1.87, 25 0 M0 25 C-0.39 7.74, 6.9 1.81, 25 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(1222.4242424242425 672.7020202020203) rotate(0 -43.18181818181813 0.45454545454543904)"><path d="M-0.83 0.99 C-15.56 1.08, -73.16 1.91, -87.42 1.72 M0.94 0.46 C-13.52 0.72, -70.58 0, -85.27 0.02" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1222.4242424242425 672.7020202020203) rotate(0 -43.18181818181813 0.45454545454543904)"><path d="M-61.72 -8.39 C-68.95 -7.12, -78.2 -2.25, -85.27 0.02 M-61.72 -8.39 C-67.58 -6.74, -70.89 -4.31, -85.27 0.02" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1222.4242424242425 672.7020202020203) rotate(0 -43.18181818181813 0.45454545454543904)"><path d="M-61.83 8.71 C-69.18 3.48, -78.39 1.85, -85.27 0.02 M-61.83 8.71 C-67.58 6.77, -70.87 5.62, -85.27 0.02" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1226.9696969696972 658.1565656565658) rotate(0 125.56987762451172 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">TileButton.cpp (QButton)</text></g><g transform="translate(1318.8888888888887 918.6111111111111) rotate(0 53.07018280029297 17.5)"><text x="0" y="24.668" font-family="Virgil, Segoe UI Emoji" font-size="28px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">main.cpp</text></g><g transform="translate(1284.4444444444448 785.8333333333335) rotate(0 139.84982299804688 25)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">SpriteProvider.cpp</text><text x="0" y="42.62" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">(stores all QPixmap Sprites)</text></g><g stroke-linecap="round"><g transform="translate(1268.888888888889 792.5000000000001) rotate(0 -78.8888888888888 -39.44444444444446)"><path d="M-0.72 1.11 C-27.09 -11.74, -131.06 -65.01, -157.21 -78.23 M1.11 0.65 C-25.46 -12.45, -131.29 -66.53, -157.86 -80.01" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1268.888888888889 792.5000000000001) rotate(0 -78.8888888888888 -39.44444444444446)"><path d="M-133.05 -76.97 C-140.74 -77.35, -151.08 -79.2, -157.86 -80.01 M-133.05 -76.97 C-142.62 -78.36, -149.77 -80.05, -157.86 -80.01" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1268.888888888889 792.5000000000001) rotate(0 -78.8888888888888 -39.44444444444446)"><path d="M-140.81 -61.73 C-145.36 -67.94, -152.71 -75.68, -157.86 -80.01 M-140.81 -61.73 C-147.57 -68.47, -151.97 -75.57, -157.86 -80.01" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1183.3333333333335 726.9444444444446) rotate(0 112.28987121582031 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">QPixmap getSprite(id)</text></g><g transform="translate(933.3333333333333 818.0555555555557) rotate(0 112.28987121582031 12.5)"><text x="0" y="17.619999999999997" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">QPixmap getSprite(id)</text></g><g stroke-linecap="round"><g transform="translate(1272.2222222222224 836.784364824992) rotate(0 -393.33333333333337 -97.142182412496)"><path d="M0.45 0.38 C-130.53 -32.13, -655.33 -161.77, -786.53 -194.17 M-0.77 -0.46 C-131.85 -32.84, -656.28 -160.56, -787.41 -192.57" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1272.2222222222224 836.784364824992) rotate(0 -393.33333333333337 -97.142182412496)"><path d="M-762.56 -195.31 C-768.09 -194.31, -774.72 -193.98, -787.41 -192.57 M-762.56 -195.31 C-769.74 -193.76, -777.78 -192.73, -787.41 -192.57" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1272.2222222222224 836.784364824992) rotate(0 -393.33333333333337 -97.142182412496)"><path d="M-766.62 -178.69 C-771.26 -181.85, -776.88 -185.66, -787.41 -192.57 M-766.62 -178.69 C-772.53 -182.55, -779.25 -186.94, -787.41 -192.57" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(1034.4444444444446 784.7222222222223) rotate(0 1.6666666666667425 15.555555555555543)"><path d="M0.18 0.32 C0.72 5.52, 2.69 26.35, 3.2 31.54 M-0.38 0.01 C0.08 5.03, 2.16 25.7, 2.7 30.79" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(1351.1111111111113 908.0555555555557) rotate(0 10.201238247079914 -28.333333333333258)"><path d="M-0.46 0.92 C2.78 -8.25, 16.75 -46.17, 20.2 -55.79 M1.5 0.36 C4.49 -9.08, 16.16 -48.13, 19.14 -57.45" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1351.1111111111113 908.0555555555557) rotate(0 10.201238247079914 -28.333333333333258)"><path d="M20.4 -32.48 C21.63 -41.95, 21.1 -51, 19.14 -57.45 M20.4 -32.48 C20.49 -39.78, 19.35 -46.28, 19.14 -57.45" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1351.1111111111113 908.0555555555557) rotate(0 10.201238247079914 -28.333333333333258)"><path d="M4.06 -37.51 C11.24 -45.08, 16.68 -52.29, 19.14 -57.45 M4.06 -37.51 C8.96 -43.4, 12.59 -48.42, 19.14 -57.45" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1361.1111111111109 878.1000000000004) rotate(0 158.83984375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">initialize (load hdf5 spritesheet)</text></g><g stroke-linecap="round"><g transform="translate(1305.5555555555557 936.9444444444446) rotate(0 -63.33333333333337 -0.5555555555555429)"><path d="M-0.43 0.11 C-21.48 -0.3, -105.83 -1.88, -126.74 -2.19 M1.55 -0.87 C-19.63 -1.19, -106.43 -1.24, -127.72 -1.22" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1305.5555555555557 936.9444444444446) rotate(0 -63.33333333333337 -0.5555555555555429)"><path d="M-104.23 -9.77 C-110.24 -7.71, -118.44 -3.97, -127.72 -1.22 M-104.23 -9.77 C-109.28 -8.07, -116.44 -5.49, -127.72 -1.22" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(1305.5555555555557 936.9444444444446) rotate(0 -63.33333333333337 -0.5555555555555429)"><path d="M-104.23 7.33 C-110.28 4.87, -118.48 4.08, -127.72 -1.22 M-104.23 7.33 C-109.11 4.8, -116.27 3.14, -127.72 -1.22" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g></g><mask></mask><g transform="translate(1203.3333333333335 930.2777777777778) rotate(0 55.729949951171875 25)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">construct</text><text x="0" y="42.62" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">MainWindow</text></g><g transform="translate(542.2222222222224 121.38888888888903) rotate(0 113.79843139648438 17.5)"><text x="0" y="24.668" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="28px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">EventHandler.cpp</text></g><g transform="translate(511.1111111111113 154.16666666666674) rotate(0 155.94985961914062 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#f08c00" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onLevelNameUpdated(new_name)</text></g><g transform="translate(834.4444444444443 1134.1666666666667) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#f08c00" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(560 378.61111111111126) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#f08c00" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(835.5555555555554 1156.388888888889) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(835.5555555555554 1179.7222222222222) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#2f9e44" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(835.5555555555554 1199.7222222222222) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(508.88888888888914 182.5000000000001) rotate(0 164.08982849121094 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#2f9e44" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onLevelWriteRequested(file_path)</text></g><g transform="translate(564.4444444444448 209.16666666666686) rotate(0 102.21990203857422 37.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onTileEntered(index)</text><text x="0" y="42.62" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onTileExited(index)</text><text x="0" y="67.62" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onTileClicked(index)</text></g><g stroke-linecap="round" transform="translate(467.77777777777806 95.83333333333348) rotate(0 190 127.2222222222222)"><path d="M32 0 C99.31 1.79, 168.77 1.21, 348 0 M32 0 C134.98 1.12, 238.33 0.36, 348 0 M348 0 C368.49 1.03, 378.15 12.6, 380 32 M348 0 C367.35 0.61, 377.88 9.94, 380 32 M380 32 C380.1 84.74, 379.31 141.3, 380 222.44 M380 32 C379.97 96.79, 379.78 163.12, 380 222.44 M380 222.44 C379.4 245.48, 370.62 255.32, 348 254.44 M380 222.44 C380.23 242.57, 371.38 252.49, 348 254.44 M348 254.44 C272.94 254.7, 197.6 254.59, 32 254.44 M348 254.44 C245.83 254.63, 142.8 255.15, 32 254.44 M32 254.44 C10.8 252.83, -1.78 243.8, 0 222.44 M32 254.44 C12.95 253.63, 0.02 245.45, 0 222.44 M0 222.44 C-2.03 149.77, -3.34 73.88, 0 32 M0 222.44 C-0.58 178.42, 0.62 131.73, 0 32 M0 32 C-1.19 9.19, 11.9 -1.93, 32 0 M0 32 C0.07 9.73, 11.54 -1.03, 32 0" stroke="#1e1e1e" stroke-width="1" fill="none"></path></g><g transform="translate(544.4444444444446 281.38888888888897) rotate(0 118.32988739013672 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onNewTileIdSelected(id)</text></g><g transform="translate(572.2222222222222 305.83333333333354) rotate(0 83.0199203491211 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">onZoomed(delta)</text></g><g transform="translate(186.66666666666674 321.38888888888897) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#f08c00" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(1274.4444444444446 680.2777777777778) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(10 552.5000000000001) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1971c2" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(1306.6666666666665 499.16666666666674) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#2f9e44" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(786.6666666666665 381.38888888888897) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(1048.8888888888887 418.05555555555566) rotate(0 35.119964599609375 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits]</text></g><g transform="translate(462.2222222222224 1178.0555555555557) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(962.2222222222224 342.50000000000017) rotate(0 60.47992706298828 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites]</text></g><g transform="translate(532.2222222222224 55.83333333333326) rotate(0 133.99624633789062 20)"><text x="0" y="14.096" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">connects emitters and overwriters</text><text x="0" y="34.096000000000004" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">makes interaction possible</text></g><g transform="translate(20.000000000000114 191.38888888888897) rotate(0 224.7923583984375 40)"><text x="0" y="14.096" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Legende:</text><text x="0" y="34.096000000000004" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[emits] -> dispatches event handler event method</text><text x="0" y="54.096000000000004" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">[overwrites] -> inherits from EventHandler and</text><text x="0" y="74.096" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic"> overwrites event method</text></g><g transform="translate(40.00000000000023 10) rotate(0 184.9500732421875 67.5)"><text x="0" y="31.716" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Formless </text><text x="0" y="76.71600000000001" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">System Architecture </text><text x="0" y="121.71600000000001" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Diagramm</text></g></svg> \ No newline at end of file diff --git a/src/editor/AutomateButton.cpp b/src/editor/AutomateButton.cpp index c8286160e2849b5bc01ea9d5c029eb09592239ad..bf549696a5d34962d5d3f877040f6652c503949a 100644 --- a/src/editor/AutomateButton.cpp +++ b/src/editor/AutomateButton.cpp @@ -1,24 +1,24 @@ /** -* TileSelector.cpp -* -* @date 06.02.2025 -* @author Nils Jonathan Friedrich Eckardt implementation -*/ + * TileSelector.cpp + * + * @date 06.02.2025 + * @author Nils Jonathan Friedrich Eckardt implementation + */ #include "AutomateButton.hpp" #include "EventHandler.hpp" -#include <QMessageBox> #include <QEvent> +#include <QMessageBox> namespace editor { -AutomateButton::AutomateButton(const QString text, QWidget* parent) : QCheckBox(text,parent) +AutomateButton::AutomateButton(const QString text, QWidget* parent) : QCheckBox(text, parent) { setChecked(false); } -void AutomateButton::mousePressEvent(QMouseEvent *event) +void AutomateButton::mousePressEvent(QMouseEvent* event) { QCheckBox::mousePressEvent(event); EventHandler::send([](EventHandler* e) { e->onCheckBoxToggled(); }); diff --git a/src/editor/EventHandler.hpp b/src/editor/EventHandler.hpp index ebc317b2763312930a404b44b8c0afdf2a6aa9e1..91a3357116e1ec6179b18ffac675a13dffbcda2a 100644 --- a/src/editor/EventHandler.hpp +++ b/src/editor/EventHandler.hpp @@ -1,19 +1,19 @@ /** -* EventHandler.cpp -* -* @date 29.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -* @author Nils Jonathan Friedrich Eckardt onCheckBoxToggle added -*/ + * EventHandler.cpp + * + * @date 29.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + * @author Nils Jonathan Friedrich Eckardt onCheckBoxToggle added + */ #pragma once -#include <cstdint> -#include <vector> +#include <QString> #include <algorithm> -#include <iostream> +#include <cstdint> #include <functional> -#include <QString> +#include <iostream> +#include <vector> namespace editor { @@ -23,11 +23,11 @@ class Tile; /** * EventHandler is the backbone in the architecture that makes interaction possible. - * + * * Classes that want to act on specific LevelEditor Events can subclass EventHandler * and overwrite the methods for the events they want to handle. If they don't overwrite * an event method the default implemenatation (doing nothing) is provided by EventHandler. - * + * * EventHandler stores all instances of EventHandler subclasses in a static variable. * Events can be emitted from anywhere in the program by using the static send method. * Emitting an event can be achieved by providing a callback to the send method that @@ -35,87 +35,89 @@ class Tile; * on it. The static send method will invoke that event method for every EventHandler instance * from the static instances variable. */ -class EventHandler { -public: - /** - * Saves a pointer to itself in the instances variable at construction. - */ - EventHandler(); - - /** - * Removes the pointer to itself from the instances variable at deconstruction. - */ - virtual ~EventHandler(); - - /** - * Executes the provided callback for every EventHandler instance from the static instances variable. - * @param callback The callback that executes the desired event method. - * It will be executed for every EventHandler instance. - */ - static void send(std::function<void(EventHandler*)> callback); - - /** - * Overwrite this event method to handle the dispatch of a new level name - * by the level name edit field. - * @param new_name The new level name. - */ - virtual void onLevelNameUpdated(std::string new_name){}; - - /** - * Overwrite this event method to handle the dispatch of a request to write - * the level to disk by the save button. - * @param file_path The path to the file into which the level should be written. - */ - virtual void onLevelWriteRequested(QString file_path){}; - - /** - * Overwrite this event method to handle the dispatch of a new tile index due - * to the mouse entering its boundaries. - * @param index The index of the entered tile. - */ - virtual void onTileEntered(int index){}; - - /** - * Overwrite this event method to handle the dispatch of a new tile index due - * to the mouse leaving its boundaries. - * @param index The index of the exited tile. - */ - virtual void onTileExited(int index){}; - - /** - * Overwrite this event method to handle the dispatch of a new tile index due - * to the user clicking it. - * @param index The index of the clicked tile. - */ - virtual void onTileClicked(int index){}; - - /** - * Overwrite this event method to handle the dispatch of a new tile_id due to - * the user selecting a different tile type in the TileSelector on the right. - * @param tile_id Id of the tile to use when an existing tile is clicked on the levelmap. - */ - virtual void onNewTileIdSelected(uint8_t tile_id){}; - - /** - * Overwrite this event method to handle the change of tile placement method due - * to the user selecting automatic tile placement assisstance. - * @param isToggled Boolean that enables tile placing assisstment. - */ - virtual void onCheckBoxToggled(){}; - - /** - * Overwrite this event method to handle the dispatch of a new delta due to - * the user pressing the zoom in or zoom out button. - * @param delta Amount to zoom in or out, e.g 0.2 => 20% in, -0.2 => 20% out. - */ - virtual void onZoomed(double delta){} - -private: - /** - * Stores all existing EventHandler instances so that the send method can - * invoke the emiited event method on every existing instance. - */ - static std::vector<EventHandler*> instances ; +class EventHandler +{ + public: + /** + * Saves a pointer to itself in the instances variable at construction. + */ + EventHandler(); + + /** + * Removes the pointer to itself from the instances variable at deconstruction. + */ + virtual ~EventHandler(); + + /** + * Executes the provided callback for every EventHandler instance from the static instances + * variable. + * @param callback The callback that executes the desired event method. + * It will be executed for every EventHandler instance. + */ + static void send(std::function<void(EventHandler*)> callback); + + /** + * Overwrite this event method to handle the dispatch of a new level name + * by the level name edit field. + * @param new_name The new level name. + */ + virtual void onLevelNameUpdated(std::string /*newName*/){}; + + /** + * Overwrite this event method to handle the dispatch of a request to write + * the level to disk by the save button. + * @param file_path The path to the file into which the level should be written. + */ + virtual void onLevelWriteRequested(QString /*filePath*/){}; + + /** + * Overwrite this event method to handle the dispatch of a new tile index due + * to the mouse entering its boundaries. + * @param index The index of the entered tile. + */ + virtual void onTileEntered(int /*index*/) {}; + + /** + * Overwrite this event method to handle the dispatch of a new tile index due + * to the mouse leaving its boundaries. + * @param index The index of the exited tile. + */ + virtual void onTileExited(int /*index*/) {}; + + /** + * Overwrite this event method to handle the dispatch of a new tile index due + * to the user clicking it. + * @param index The index of the clicked tile. + */ + virtual void onTileClicked(int /*index*/) {}; + + /** + * Overwrite this event method to handle the dispatch of a new tile_id due to + * the user selecting a different tile type in the TileSelector on the right. + * @param tile_id Id of the tile to use when an existing tile is clicked on the levelmap. + */ + virtual void onNewTileIdSelected(uint8_t /*tileId*/) {}; + + /** + * Overwrite this event method to handle the change of tile placement method due + * to the user selecting automatic tile placement assisstance. + * @param isToggled Boolean that enables tile placing assisstment. + */ + virtual void onCheckBoxToggled() {}; + + /** + * Overwrite this event method to handle the dispatch of a new delta due to + * the user pressing the zoom in or zoom out button. + * @param delta Amount to zoom in or out, e.g 0.2 => 20% in, -0.2 => 20% out. + */ + virtual void onZoomed(double /*delta*/) {} + + private: + /** + * Stores all existing EventHandler instances so that the send method can + * invoke the emiited event method on every existing instance. + */ + static std::vector<EventHandler*> instances; }; } // namespace editor \ No newline at end of file diff --git a/src/editor/LevelNameEdit.cpp b/src/editor/LevelNameEdit.cpp index c6debb46246d6853cda20f7efbd80a9d2b4ec790..a1611a4c198d7524105634cd6ec4f336444da513 100644 --- a/src/editor/LevelNameEdit.cpp +++ b/src/editor/LevelNameEdit.cpp @@ -1,9 +1,9 @@ /** -* EventHandler.cpp -* -* @date 29.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * EventHandler.cpp + * + * @date 29.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "LevelNameEdit.hpp" @@ -14,18 +14,18 @@ namespace editor { -LevelNameEdit::LevelNameEdit(const std::string& level_name, QWidget* parent) : QLineEdit(parent) +LevelNameEdit::LevelNameEdit(const std::string& levelName, QWidget* parent) : QLineEdit(parent) { setFixedWidth(150); - setText(level_name.c_str()); // prefill level name + setText(levelName.c_str()); // prefill level name } void LevelNameEdit::keyPressEvent(QKeyEvent* event) { QLineEdit::keyPressEvent(event); - std::string new_name = text().toStdString(); + std::string newName = text().toStdString(); // dispatch the level name updated event method to allow all depending Widgets to take action - EventHandler::send([new_name](EventHandler* e) { e->onLevelNameUpdated(new_name); }); + EventHandler::send([newName](EventHandler* e) { e->onLevelNameUpdated(newName); }); } } // namespace editor \ No newline at end of file diff --git a/src/editor/LevelNameEdit.hpp b/src/editor/LevelNameEdit.hpp index 1ce0265a6b0f93ecc3ebb9510a9ea1507fe26dcb..3cc97c308364d8a41886a80d03adcd4d7e29fb84 100644 --- a/src/editor/LevelNameEdit.hpp +++ b/src/editor/LevelNameEdit.hpp @@ -1,32 +1,34 @@ /** -* EventHandler.cpp -* -* @date 29.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * EventHandler.cpp + * + * @date 29.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #pragma once #include <QLineEdit> -namespace editor +namespace editor { /** * The LevelNameEdit Widget is displayed on the left of the TopBar. * It allows the user to set a custom level name. */ -class LevelNameEdit : public QLineEdit { -public: - /** - * Creates a LevelNameEdit Widget prefilling the provided level_name. - * The parent of the LevelNameEdit Widget is set to the provided parent. - * @param level_name The initial name of the level. - * @param parent The Widget that should be set as the parent of this Widget. - */ - LevelNameEdit(const std::string& level_name, QWidget* parent = nullptr); -protected: - void keyPressEvent(QKeyEvent* event) override; +class LevelNameEdit : public QLineEdit +{ + public: + /** + * Creates a LevelNameEdit Widget prefilling the provided level_name. + * The parent of the LevelNameEdit Widget is set to the provided parent. + * @param level_name The initial name of the level. + * @param parent The Widget that should be set as the parent of this Widget. + */ + LevelNameEdit(const std::string& levelName, QWidget* parent = nullptr); + + protected: + void keyPressEvent(QKeyEvent* event) override; }; } // namespace editor \ No newline at end of file diff --git a/src/editor/LevelScene.cpp b/src/editor/LevelScene.cpp index 836e9174b773f6ed3018495fa29615391273ccf0..e1f6fd6bad6592c722fab459a3db84231070ffda 100644 --- a/src/editor/LevelScene.cpp +++ b/src/editor/LevelScene.cpp @@ -1,10 +1,10 @@ /** -* LevelScene.cpp -* -* @date 28.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -* @author Nils Jonathan Friedrich Eckardt implemented advanced placement -*/ + * LevelScene.cpp + * + * @date 28.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + * @author Nils Jonathan Friedrich Eckardt implemented advanced placement + */ #include "LevelScene.hpp" @@ -14,34 +14,33 @@ #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> - -#include "highfive/H5File.hpp" #include "SpriteProvider.hpp" +#include "highfive/H5File.hpp" namespace editor { LevelScene::LevelScene( const std::string& name, int width, int height, std::vector<uint8_t> tile_ids, - const std::string& file_path, QWidget* parent) - : QGraphicsScene(parent), m_name(name), m_width(width), m_height(height), m_tile_ids(tile_ids), - m_file_path(file_path), m_selected_tile_id(2) + const std::string& filePath, QWidget* parent) + : QGraphicsScene(parent), m_selected_tile_id(2), m_name(name), m_advanced_tile_placement(false), + m_width(width), m_height(height), m_tile_ids(tile_ids), m_tile_occupants({}), + m_file_path(filePath) { setSceneRect(0, 0, m_width * 16, m_height * 16); - m_advanced_tile_placement = false; - m_tile_occupants = {}; + m_tile_occupants.reserve(tile_ids.size()); for (int index = 0; index < tile_ids.size(); index++) { int x = (index % m_width) * 16; int y = (index / m_width) * 16; - Tile* tile = new Tile(index, is_border(index) ? tile_ids[index] : 0); + Tile* tile = new Tile(index, isBorder(index) ? tile_ids[index] : 0); addItem(tile); tile->setZValue(0); tile->setPos(x, y); - if (!is_border(index) && tile_ids[index] > 0) + if (!isBorder(index) && tile_ids[index] > 0) { - m_tile_occupants.push_back(occupy_tile(index, tile_ids[index])); + m_tile_occupants.push_back(occupyTile(index, tile_ids[index])); } else { @@ -53,56 +52,60 @@ LevelScene::LevelScene( LevelScene* LevelScene::empty(const std::string& name, int width, int height, QWidget* parent) { // + 2 because of surrounding the map with cliffs - std::vector<uint8_t> tile_ids; - tile_ids.reserve(width*height); + std::vector<uint8_t> tileIds; + tileIds.reserve(width * height); // create top row with cliffs - tile_ids.push_back(22); // cliff corner top left - for (int i = 0; i < width - 2; i++) { - tile_ids.push_back(19); // cliff bottom + tileIds.push_back(22); // cliff corner top left + for (int i = 0; i < width - 2; i++) + { + tileIds.push_back(19); // cliff bottom } - tile_ids.push_back(23); // cliff corner top right + tileIds.push_back(23); // cliff corner top right // create main rows with cliff at start and end - for (int i = 0; i < height - 2; i++) { - tile_ids.push_back(21); // cliff right - for (int j = 0; j < width - 2; j++) { - tile_ids.push_back(0); // pleins + for (int i = 0; i < height - 2; i++) + { + tileIds.push_back(21); // cliff right + for (int j = 0; j < width - 2; j++) + { + tileIds.push_back(0); // pleins } - tile_ids.push_back(20); // cliff left + tileIds.push_back(20); // cliff left } // create bottom row with cliffs - tile_ids.push_back(24); // cliff corner bottom left - for (int i = 0; i < width - 2; i++) { - tile_ids.push_back(18); // cliff top + tileIds.push_back(24); // cliff corner bottom left + for (int i = 0; i < width - 2; i++) + { + tileIds.push_back(18); // cliff top } - tile_ids.push_back(25); // cliff corner bottom right + tileIds.push_back(25); // cliff corner bottom right - return new LevelScene(name, width, height, tile_ids, "../res/level_new.h5", parent); + return new LevelScene(name, width, height, tileIds, "../res/level_new.h5", parent); } -LevelScene* LevelScene::fromFile(const std::string& file_path, QWidget* parent) +LevelScene* LevelScene::fromFile(const std::string& filePath, QWidget* parent) { - HighFive::File file(file_path, HighFive::File::ReadOnly); + HighFive::File file(filePath, HighFive::File::ReadOnly); // read level metadata - std::string level_metadata; - file.getDataSet("metadata").read(level_metadata); + std::string levelMetadata; + file.getDataSet("metadata").read(levelMetadata); // read tilesarray - std::vector<uint8_t> level_tilesarray; - file.getDataSet("tilesarray").read(level_tilesarray); + std::vector<uint8_t> levelTilesarray; + file.getDataSet("tilesarray").read(levelTilesarray); // extract metadata from xml - std::istringstream xmlStream(level_metadata); + std::istringstream xmlStream(levelMetadata); boost::property_tree::ptree pt; boost::property_tree::read_xml(xmlStream, pt); int width = pt.get<int>("level.width"); int height = pt.get<int>("level.height"); std::string name = pt.get<std::string>("level.name"); - return new LevelScene(name, width, height, level_tilesarray, file_path, parent); + return new LevelScene(name, width, height, levelTilesarray, filePath, parent); } std::string LevelScene::getName() @@ -120,17 +123,15 @@ int LevelScene::getHeight() return m_height; } -bool LevelScene::is_border(int index) +bool LevelScene::isBorder(int index) { - return (index / m_width) == 0 - || (index / m_width) == (m_height -1) - || (index % m_width) == 0 - || (index % m_width) == (m_width - 1); + return (index / m_width) == 0 || (index / m_width) == (m_height - 1) || + (index % m_width) == 0 || (index % m_width) == (m_width - 1); } -bool LevelScene::is_water_tile(uint8_t id) +bool LevelScene::isWaterTile(uint8_t id) { - if (id == 1) + if (id == 1) { return true; } @@ -141,12 +142,12 @@ bool LevelScene::is_water_tile(uint8_t id) return false; } -void LevelScene::onLevelNameUpdated(std::string new_name) +void LevelScene::onLevelNameUpdated(std::string newName) { - m_name = new_name; + m_name = newName; } -void LevelScene::onLevelWriteRequested(QString file_path) +void LevelScene::onLevelWriteRequested(QString filePath) { boost::property_tree::ptree pt; @@ -158,12 +159,12 @@ void LevelScene::onLevelWriteRequested(QString file_path) // convert property tree to xml string std::ostringstream xmlStream; boost::property_tree::write_xml(xmlStream, pt); - std::string xml_data = xmlStream.str(); + std::string xmlData = xmlStream.str(); // write level to hdf5 - HighFive::File file(file_path.toStdString(), HighFive::File::Truncate); + HighFive::File file(filePath.toStdString(), HighFive::File::Truncate); file.createDataSet<std::string>("metadata", HighFive::DataSpace::From(xmlStream)) - .write(xml_data); + .write(xmlData); file.createDataSet<uint8_t>("tilesarray", HighFive::DataSpace::From(m_tile_ids)) .write(m_tile_ids); } @@ -174,7 +175,7 @@ void LevelScene::onTileEntered(int index) { return; } - if (is_border(index) && !is_water_tile(m_selected_tile_id)) + if (isBorder(index) && !isWaterTile(m_selected_tile_id)) { return; } @@ -184,9 +185,9 @@ void LevelScene::onTileEntered(int index) delete m_tile_occupants[index]; m_tile_occupants[index] = nullptr; } - if (!is_border(index) && m_selected_tile_id > 0 || is_border(index)) + if ((!isBorder(index) && m_selected_tile_id > 0) || isBorder(index)) { - m_tile_occupants[index] = occupy_tile(index, m_selected_tile_id); + m_tile_occupants[index] = occupyTile(index, m_selected_tile_id); } } @@ -204,13 +205,13 @@ void LevelScene::onTileExited(int index) } if (m_tile_ids[index] > 0) { - m_tile_occupants[index] = occupy_tile(index, m_tile_ids[index]); + m_tile_occupants[index] = occupyTile(index, m_tile_ids[index]); } } void LevelScene::setTile(int index, uint8_t id) { - m_tile_ids[index]=id; + m_tile_ids[index] = id; if (m_tile_occupants[index] != nullptr) { removeItem(m_tile_occupants[index]); @@ -219,10 +220,10 @@ void LevelScene::setTile(int index, uint8_t id) } if (m_tile_ids[index] > 0) { - m_tile_occupants[index] = occupy_tile(index, id); + m_tile_occupants[index] = occupyTile(index, id); } - /* gespiegeltes Setzen + /* gespiegeltes Setzen index = m_width * m_height - 1 -index; int swapID[22] ={11,10,9,8,12,16,15,14,13,17,19,18,21,20,25,24,23,22,29,28,27,26}; if(id > 7 && id < 30) id = swapID[ id-8 ]; @@ -243,40 +244,47 @@ void LevelScene::setTile(int index, uint8_t id) void LevelScene::onTileClicked(int index) { - if (is_border(index) && !is_water_tile(m_selected_tile_id)) { - return; - } - - if (!m_advanced_tile_placement) { - m_tile_ids[index] = m_selected_tile_id; - return; - } - - - if(m_selected_tile_id > 5 && m_selected_tile_id < 17){ //Straße plaziert - placeRoad(index, true); - return; - } - if((m_selected_tile_id > 16 && m_selected_tile_id < 30) || m_selected_tile_id == 1){ //Wasser plaziert - if(m_selected_tile_id == 17){ - setTile(index,17); - } else { - setTile(index,1); - } - placeCliff(false, index); - return; - } - if(m_selected_tile_id == 0 || m_selected_tile_id == 2 || m_selected_tile_id == 3){ //Land plaziert - setTile(index,m_selected_tile_id); - placeCliff(true, index); - return; - } - setTile(index, m_selected_tile_id); //Gebäude plaziert + if (isBorder(index) && !isWaterTile(m_selected_tile_id)) + { + return; + } + + if (!m_advanced_tile_placement) + { + m_tile_ids[index] = m_selected_tile_id; + return; + } + + if (m_selected_tile_id > 5 && m_selected_tile_id < 17) + { // Straße plaziert + placeRoad(index, true); + return; + } + if ((m_selected_tile_id > 16 && m_selected_tile_id < 30) || m_selected_tile_id == 1) + { // Wasser plaziert + if (m_selected_tile_id == 17) + { + setTile(index, 17); + } + else + { + setTile(index, 1); + } + placeCliff(false, index); + return; + } + if (m_selected_tile_id == 0 || m_selected_tile_id == 2 || m_selected_tile_id == 3) + { // Land plaziert + setTile(index, m_selected_tile_id); + placeCliff(true, index); + return; + } + setTile(index, m_selected_tile_id); // Gebäude plaziert } -void LevelScene::onNewTileIdSelected(uint8_t tile_id) +void LevelScene::onNewTileIdSelected(uint8_t tileId) { - m_selected_tile_id = tile_id; + m_selected_tile_id = tileId; } void LevelScene::onCheckBoxToggled() @@ -284,212 +292,352 @@ void LevelScene::onCheckBoxToggled() m_advanced_tile_placement = !m_advanced_tile_placement; } -QGraphicsPixmapItem* LevelScene::occupy_tile(int index, uint8_t tile_id) +QGraphicsPixmapItem* LevelScene::occupyTile(int index, uint8_t tileId) { int x = (index % m_width) * 16; int y = (index / m_width) * 16; - QPixmap tile_occupant = SpriteProvider::get_sprite(tile_id); - QGraphicsPixmapItem* tile_occupant_item = addPixmap(tile_occupant); - tile_occupant_item->setZValue(tile_id < 50 ? 1 : 2 + index); - tile_occupant_item->setPos(x, tile_id < 50 ? y : y - 16); - return tile_occupant_item; + QPixmap tileOccupant = SpriteProvider::getSprite(tileId); + QGraphicsPixmapItem* tileOccupantItem = addPixmap(tileOccupant); + tileOccupantItem->setZValue(tileId < 50 ? 1 : 2 + index); + tileOccupantItem->setPos(x, tileId < 50 ? y : y - 16); + return tileOccupantItem; } +void LevelScene::placeCliff(bool placedLand, int index) +{ + const int16_t IdToSum[12] = {12, 3, 9, 6, 2, 1, 4, 8, 13, 14, 11, 7}; + const int16_t SumToId[16] = {1, 23, 22, 19, 24, 24, 21, 29, 25, 20, 25, 28, 18, 26, 27, 0}; + + int16_t surroundingIDs[8] = {-2, -2, -2, -2, + -2, -2, -2, -2}; //-2 = uninitialisiert, -1 = kartenrand + bool marchingSquares[8][4] = {{false}}; + + // Überprüfe Kartenränder, setze diese auf -1 + if (index < m_width) + { // oberer Kartenrand + surroundingIDs[7] = -1; + surroundingIDs[0] = -1; + surroundingIDs[1] = -1; + } + if ((index + 1) % m_width == 0) + { // rechter Kartenrand + surroundingIDs[1] = -1; + surroundingIDs[2] = -1; + surroundingIDs[3] = -1; + } + if (index >= m_width * (m_height - 1)) + { // unterer Kartenrand + surroundingIDs[3] = -1; + surroundingIDs[4] = -1; + surroundingIDs[5] = -1; + } + if (index % m_width == 0) + { // linker Kartenrand + surroundingIDs[5] = -1; + surroundingIDs[6] = -1; + surroundingIDs[7] = -1; + } + // Erhalte IDs von den umliegenden 8 Feldern, die kein Kartenrand sind + // startet in der mitte Oben, gehe im Uhrzeigersinn + if (surroundingIDs[0] == -2) + { + surroundingIDs[0] = (int16_t)m_tile_ids[index - m_width]; + } + if (surroundingIDs[1] == -2) + { + surroundingIDs[1] = (int16_t)m_tile_ids[index - m_width + 1]; + } + if (surroundingIDs[2] == -2) + { + surroundingIDs[2] = (int16_t)m_tile_ids[index + 1]; + } + if (surroundingIDs[3] == -2) + { + surroundingIDs[3] = (int16_t)m_tile_ids[index + m_width + 1]; + } + if (surroundingIDs[4] == -2) + { + surroundingIDs[4] = (int16_t)m_tile_ids[index + m_width]; + } + if (surroundingIDs[5] == -2) + { + surroundingIDs[5] = (int16_t)m_tile_ids[index + m_width - 1]; + } + if (surroundingIDs[6] == -2) + { + surroundingIDs[6] = (int16_t)m_tile_ids[index - 1]; + } + if (surroundingIDs[7] == -2) + { + surroundingIDs[7] = (int16_t)m_tile_ids[index - m_width - 1]; + } + // Ids können nicht lesbare Tiles enthalten, diese Herausfiltern + for (short& surroundingID : surroundingIDs) + { + if (surroundingID == 17) + { + surroundingID = 1; // Riff als Wasser angesehen + } + if (surroundingID == 2 || surroundingID == 3) + { + surroundingID = 0; // Wald, Gebirge als Land angesehen + } + if (surroundingID > 3 && surroundingID < 17) + { + surroundingID = -1; // Straßen werden nicht verändert + } + if (surroundingID > 29) + { + surroundingID = 0; // Gebäude werden als Land angesehen + } + } + // ID remapping um damit arbeiten zu können + for (short& surroundingID : surroundingIDs) + { + if (surroundingID == -1) + { + } + else if (surroundingID == 0) + { + surroundingID = 15; + } + else if (surroundingID == 1) + { + surroundingID = 0; + } + else + { + surroundingID = IdToSum[surroundingID - 18]; + } + } + // Berechne Marching Squares aus der remapped Id + for (int i = 0; i < 8; i++) + { + if (surroundingIDs[i] / 8 == 1) + { + marchingSquares[i][0] = true; // top left + surroundingIDs[i] -= 8; + } + if (surroundingIDs[i] / 4 == 1) + { + marchingSquares[i][1] = true; // top right + surroundingIDs[i] -= 4; + } + if (surroundingIDs[i] / 2 == 1) + { + marchingSquares[i][2] = true; // bottom right + surroundingIDs[i] -= 2; + } + if (surroundingIDs[i] == 1) + { + marchingSquares[i][3] = true; // bottom left + } + } + // Einfügen/Abziehen des Landes + marchingSquares[0][2] = placedLand; // oben + marchingSquares[0][3] = placedLand; + marchingSquares[1][3] = placedLand; // oben rechts + marchingSquares[2][3] = placedLand; // rechts + marchingSquares[2][0] = placedLand; + marchingSquares[3][0] = placedLand; // untern rechts + marchingSquares[4][0] = placedLand; // unten + marchingSquares[4][1] = placedLand; + marchingSquares[5][1] = placedLand; // unten links + marchingSquares[6][1] = placedLand; // links + marchingSquares[6][2] = placedLand; + marchingSquares[7][2] = placedLand; // oben links + + // Berechne remapped ID aus Marching Squares + for (int i = 0; i < 8; i++) + { + if (surroundingIDs[i] > -1) + { + surroundingIDs[i] = 0; + if (marchingSquares[i][0]) + { + surroundingIDs[i] += 8; + } + if (marchingSquares[i][1]) + { + surroundingIDs[i] += 4; + } + if (marchingSquares[i][2]) + { + surroundingIDs[i] += 2; + } + if (marchingSquares[i][3]) + { + surroundingIDs[i] += 1; + } + } + } + // Remappe ID für setzbare Tiles + for (int i = 0; i < 8; i++) + { + if (surroundingIDs[i] > -1) + { + surroundingIDs[i] = SumToId[surroundingIDs[i]]; + } + } + // Plaziere Tiles + for (int i = 0; i < 8; i++) + { + if (isntIdentical(surroundingIDs[i], calcDir(i, index))) + { + setTile(calcDir(i, index), (uint8_t)surroundingIDs[i]); + } + } +} +void LevelScene::placeRoad(int index, bool updateFlag) +{ + const int16_t IdToSum[] = {5, 10, 13, 14, 11, 7, 15, 6, 3, 12, 9}; + const uint8_t SumToId[] = {6, 6, 7, 14, 6, 6, 13, 11, 7, 16, 7, 10, 15, 8, 9, 12}; + bool tileDirections[] = {false, false, false, false}; + int16_t surroundingIDs[] = {-1, -1, -1, -1}; //-1 = kartenrand oder keine strasse + uint8_t placedID = 0; + // Erhalte IDs der umliegenden Felder - im Uhrzeigersinn, start: oben + // Vorgehen: überprüfe, ob die obere Zelle im Kartenrand ist. Wenn nicht erhalte index der + // oberen Zelle + if (!(index < m_width)) + { + surroundingIDs[0] = (int16_t)m_tile_ids[index - m_width]; + } + if (!((index + 1) % m_width == 0)) + { + surroundingIDs[1] = (int16_t)m_tile_ids[index + 1]; + } + if (!(index > m_width * (m_height - 1))) + { + surroundingIDs[2] = (int16_t)m_tile_ids[index + m_width]; + } + if (!(index % m_width == 0)) + { + surroundingIDs[3] = (int16_t)m_tile_ids[index - 1]; + } + // Umformen der IDs oder ID ist keine Straße + for (int i = 0; i < 4; i++) + { + if (surroundingIDs[i] < 6 || surroundingIDs[i] > 16) + { + surroundingIDs[i] = -1; // ID ist keine Strasse + } + else + { + surroundingIDs[i] = IdToSum[surroundingIDs[i] - 6]; // id remapping + } + } - - -void LevelScene::placeCliff(bool placedLand, int index){ - const int16_t IdToSum[12] = {12,3,9,6,2,1,4,8,13,14,11,7}; - const int16_t SumToId[16] = {1,23,22,19,24,24,21,29,25,20,25,28,18,26,27,0}; - - int16_t surroundingIDs[8] = {-2,-2,-2,-2,-2,-2,-2,-2}; //-2 = uninitialisiert, -1 = kartenrand - bool marchingSquares[8][4] = {false}; - - //Überprüfe Kartenränder, setze diese auf -1 - if(index < m_width){ //oberer Kartenrand - surroundingIDs[7] = -1; - surroundingIDs[0] = -1; - surroundingIDs[1] = -1; - } - if((index + 1) % m_width == 0){ //rechter Kartenrand - surroundingIDs[1] = -1; - surroundingIDs[2] = -1; - surroundingIDs[3] = -1; - } - if(index >= m_width * (m_height - 1)){ //unterer Kartenrand - surroundingIDs[3] = -1; - surroundingIDs[4] = -1; - surroundingIDs[5] = -1; - } - if(index % m_width == 0){ //linker Kartenrand - surroundingIDs[5] = -1; - surroundingIDs[6] = -1; - surroundingIDs[7] = -1; - } - - //Erhalte IDs von den umliegenden 8 Feldern, die kein Kartenrand sind - //startet in der mitte Oben, gehe im Uhrzeigersinn - if(surroundingIDs[0] == -2) surroundingIDs[0] = (int16_t) m_tile_ids[index - m_width]; - if(surroundingIDs[1] == -2) surroundingIDs[1] = (int16_t) m_tile_ids[index - m_width + 1]; - if(surroundingIDs[2] == -2) surroundingIDs[2] = (int16_t) m_tile_ids[index + 1]; - if(surroundingIDs[3] == -2) surroundingIDs[3] = (int16_t) m_tile_ids[index + m_width + 1]; - if(surroundingIDs[4] == -2) surroundingIDs[4] = (int16_t) m_tile_ids[index + m_width]; - if(surroundingIDs[5] == -2) surroundingIDs[5] = (int16_t) m_tile_ids[index + m_width - 1]; - if(surroundingIDs[6] == -2) surroundingIDs[6] = (int16_t) m_tile_ids[index - 1]; - if(surroundingIDs[7] == -2) surroundingIDs[7] = (int16_t) m_tile_ids[index - m_width - 1]; - - //Ids können nicht lesbare Tiles enthalten, diese Herausfiltern - for(int i = 0; i < 8; i++){ - if(surroundingIDs[i] == 17) surroundingIDs[i] = 1; //Riff als Wasser angesehen - if(surroundingIDs[i] == 2 || surroundingIDs[i] == 3) surroundingIDs[i] = 0; //Wald, Gebirge als Land angesehen - if(surroundingIDs[i] > 3 && surroundingIDs[i] < 17) surroundingIDs[i] = -1; //Straßen werden nicht verändert - if(surroundingIDs[i] > 29) surroundingIDs[i] = 0; //Gebäude werden als Land angesehen - } - - //ID remapping um damit arbeiten zu können - for(int i = 0; i < 8; i++){ - if(surroundingIDs[i] == -1){ - } else if(surroundingIDs[i] == 0){ - surroundingIDs[i] = 15; - } else if(surroundingIDs[i] == 1){ - surroundingIDs[i] = 0; - } else{ - surroundingIDs[i]= IdToSum[surroundingIDs[i] - 18]; - } - } - - //Berechne Marching Squares aus der remapped Id - for(int i = 0; i < 8; i++){ - if(surroundingIDs[i] / 8 == 1){ - marchingSquares[i][0] = true; //top left - surroundingIDs[i] -= 8; - } - if(surroundingIDs[i] / 4 == 1){ - marchingSquares[i][1] = true; //top right - surroundingIDs[i] -= 4; - } - if(surroundingIDs[i] / 2 == 1){ - marchingSquares[i][2] = true; //bottom right - surroundingIDs[i] -= 2; - } - if(surroundingIDs[i] == 1){ - marchingSquares[i][3] = true; //bottom left - } - } - - //Einfügen/Abziehen des Landes - marchingSquares[0][2] = placedLand; //oben - marchingSquares[0][3] = placedLand; - marchingSquares[1][3] = placedLand; //oben rechts - marchingSquares[2][3] = placedLand; //rechts - marchingSquares[2][0] = placedLand; - marchingSquares[3][0] = placedLand; //untern rechts - marchingSquares[4][0] = placedLand; //unten - marchingSquares[4][1] = placedLand; - marchingSquares[5][1] = placedLand; //unten links - marchingSquares[6][1] = placedLand; //links - marchingSquares[6][2] = placedLand; - marchingSquares[7][2] = placedLand; //oben links - - //Berechne remapped ID aus Marching Squares - for(int i = 0; i < 8; i++){ - if(surroundingIDs[i] > -1){ - surroundingIDs[i] = 0; - if(marchingSquares[i][0]) surroundingIDs[i] += 8; - if(marchingSquares[i][1]) surroundingIDs[i] += 4; - if(marchingSquares[i][2]) surroundingIDs[i] += 2; - if(marchingSquares[i][3]) surroundingIDs[i] += 1; + // Berechne in welche Richtungen das neue Tile Zeigt + for (int i = 0; i < 4; i++) + { + if (surroundingIDs[i] > -1) + { + tileDirections[i] = true; } } - - //Remappe ID für setzbare Tiles - for(int i = 0; i < 8; i++){ - if(surroundingIDs[i] > -1) surroundingIDs[i] = SumToId[ surroundingIDs[i] ]; - } - - //Plaziere Tiles - for(int i = 0; i < 8; i++){ - if(isntIdentical(surroundingIDs[i], calcDir(i, index))) - setTile( calcDir(i, index),(uint8_t)surroundingIDs[i] ); + + // Berechne die Remapped ID + placedID = 0; + if (tileDirections[0]) + { + placedID += 8; + } + if (tileDirections[1]) + { + placedID += 4; } -} + if (tileDirections[2]) + { + placedID += 2; + } + if (tileDirections[3]) + { + placedID += 1; + } + + if (placedID == 0) + { + updateFlag = false; // Umliegende Tiles müssen nicht geupdated werden, da keine Strassen + } + placedID = SumToId[placedID]; // Berechnete Summe in Valide ID umformen + setTile(index, placedID); // Tile setzen -void LevelScene::placeRoad(int index, bool updateFlag){ - const int16_t IdToSum[] = {5,10,13,14,11,7,15,6,3,12,9}; - const uint8_t SumToId[] = {6,6,7,14,6,6,13,11,7,16,7,10,15,8,9,12}; - - bool tileDirections[] = {false,false,false,false}; - int16_t surroundingIDs[] = {-1,-1,-1,-1}; //-1 = kartenrand oder keine strasse - uint8_t placedID = 0; - - //Erhalte IDs der umliegenden Felder - im Uhrzeigersinn, start: oben - //Vorgehen: überprüfe, ob die obere Zelle im Kartenrand ist. Wenn nicht erhalte index der oberen Zelle - if(!(index < m_width)) surroundingIDs[0] = (int16_t) m_tile_ids[index - m_width]; - if(!((index + 1) % m_width == 0)) surroundingIDs[1] = (int16_t) m_tile_ids[index + 1]; - if(!(index > m_width * (m_height-1))) surroundingIDs[2] = (int16_t) m_tile_ids[index + m_width]; - if(!(index % m_width == 0)) surroundingIDs[3] = (int16_t) m_tile_ids[index - 1]; - - //Umformen der IDs oder ID ist keine Straße - for(int i = 0; i < 4; i++){ - if(surroundingIDs[i] < 6 || surroundingIDs[i] > 16){ - surroundingIDs[i] = -1; //ID ist keine Strasse - } else { - surroundingIDs[i] = IdToSum[ surroundingIDs[i] - 6]; //id remapping - } - } - - //Berechne in welche Richtungen das neue Tile Zeigt - for(int i = 0; i < 4; i++){ - if(surroundingIDs[i] > -1) tileDirections[i] = true; - } - - //Berechne die Remapped ID - placedID = 0; - if(tileDirections[0]) placedID += 8; - if(tileDirections[1]) placedID += 4; - if(tileDirections[2]) placedID += 2; - if(tileDirections[3]) placedID += 1; - - if(placedID == 0) updateFlag = false; //Umliegende Tiles müssen nicht geupdated werden, da keine Strassen - placedID = SumToId[placedID]; //Berechnete Summe in Valide ID umformen - setTile(index, placedID); //Tile setzen - - //Update umliegende Tiles - if(updateFlag){ - if(tileDirections[0]) placeRoad((index - m_width), false); //update oben - if(tileDirections[1]) placeRoad((index + 1), false); //update rechts - if(tileDirections[2]) placeRoad((index + m_width), false); //update unten - if(tileDirections[3]) placeRoad((index - 1), false); //update links - } + // Update umliegende Tiles + if (updateFlag) + { + if (tileDirections[0]) + { + placeRoad((index - m_width), false); // update oben + } + if (tileDirections[1]) + { + placeRoad((index + 1), false); // update rechts + } + if (tileDirections[2]) + { + placeRoad((index + m_width), false); // update unten + } + if (tileDirections[3]) + { + placeRoad((index - 1), false); // update links + } + } } -int LevelScene::calcDir(int i, int index){ - if(i==0) return (index - m_width); - if(i==1) return (index - m_width + 1); - if(i==2) return (index + 1); - if(i==3) return (index + m_width + 1); - if(i==4) return (index + m_width); - if(i==5) return (index + m_width - 1); - if(i==6) return (index - 1); - if(i==7) return (index - m_width - 1); +int LevelScene::calcDir(int i, int index) +{ + if (i == 0) + { + return (index - m_width); + } + if (i == 1) + { + return (index - m_width + 1); + } + if (i == 2) + { + return (index + 1); + } + if (i == 3) + { + return (index + m_width + 1); + } + if (i == 4) + { + return (index + m_width); + } + if (i == 5) + { + return (index + m_width - 1); + } + if (i == 6) + { + return (index - 1); + } + if (i == 7) + { + return (index - m_width - 1); + } } -bool LevelScene::isntIdentical(int16_t id, int index){ - bool flag = (!(id == -1 || //kartenrand - (id == 0 && m_tile_ids[index]==2) || //wald - (id == 0 && m_tile_ids[index]==3) || //gebirge - (id == 1 && m_tile_ids[index]==17)) ); //riff +bool LevelScene::isntIdentical(int16_t id, int index) +{ + bool flag = + (id != -1 && // kartenrand + (id != 0 || m_tile_ids[index] != 2) && // wald + (id != 0 || m_tile_ids[index] != 3) && // gebirge + (id != 1 || m_tile_ids[index] != 17)); // riff return flag; } diff --git a/src/editor/LevelScene.hpp b/src/editor/LevelScene.hpp index 4f69c7ecf5563e80b276a994f32c938011a86cc3..89ad83038edab4a546d01373f0643b8c8be9bf54 100644 --- a/src/editor/LevelScene.hpp +++ b/src/editor/LevelScene.hpp @@ -1,18 +1,18 @@ /** -* LevelScene.hpp -* -* @date 28.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -* @author Nils Jonathan Friedrich Eckardt minor changes -*/ + * LevelScene.hpp + * + * @date 28.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + * @author Nils Jonathan Friedrich Eckardt minor changes + */ #pragma once +#include <QGraphicsRectItem> #include <QGraphicsScene> +#include <QGraphicsSceneMouseEvent> #include <QMouseEvent> #include <QWidget> -#include <QGraphicsRectItem> -#include <QGraphicsSceneMouseEvent> #include "EventHandler.hpp" #include "Tile.hpp" @@ -20,38 +20,43 @@ namespace editor { -class LevelScene : public QGraphicsScene, public EventHandler { -public: - LevelScene(const std::string& name, int width, int height, std::vector<uint8_t> tile_ids, const std::string& file_path, QWidget *parent = nullptr); - static LevelScene* empty(const std::string& name, int width, int height, QWidget *parent = nullptr); - static LevelScene* fromFile(const std::string& file_path, QWidget *parent = nullptr); - std::string getName(); - int getWidth(); - int getHeight(); -private: - bool is_border(int index); - bool is_water_tile(uint8_t id); - bool isntIdentical(int16_t id, int index); - void onLevelNameUpdated(std::string new_name) override; - void onLevelWriteRequested(QString file_path) override; - void onTileEntered(int index) override; - void onTileExited(int index) override; - void onTileClicked(int index) override; - void onNewTileIdSelected(uint8_t tile_id) override; - void onCheckBoxToggled() override; - void setTile(int index, uint8_t id); - void placeCliff(bool placedLand, int index); - void placeRoad(int index, bool updateFlag); - int calcDir(int i, int index); - QGraphicsPixmapItem* occupy_tile(int index, uint8_t tile_id); - uint8_t m_selected_tile_id; - std::string m_name; - bool m_advanced_tile_placement; - int m_width; - int m_height; - std::vector<uint8_t> m_tile_ids; - std::vector<QGraphicsPixmapItem*> m_tile_occupants; - std::string m_file_path; +class LevelScene : public QGraphicsScene, public EventHandler +{ + public: + LevelScene( + const std::string& name, int width, int height, std::vector<uint8_t> tileIds, + const std::string& filePath, QWidget* parent = nullptr); + static LevelScene* + empty(const std::string& name, int width, int height, QWidget* parent = nullptr); + static LevelScene* fromFile(const std::string& filePath, QWidget* parent = nullptr); + std::string getName(); + int getWidth(); + int getHeight(); + + private: + bool isBorder(int index); + bool isWaterTile(uint8_t id); + bool isntIdentical(int16_t id, int index); + void onLevelNameUpdated(std::string newName) override; + void onLevelWriteRequested(QString filePath) override; + void onTileEntered(int index) override; + void onTileExited(int index) override; + void onTileClicked(int index) override; + void onNewTileIdSelected(uint8_t tileId) override; + void onCheckBoxToggled() override; + void setTile(int index, uint8_t id); + void placeCliff(bool placedLand, int index); + void placeRoad(int index, bool updateFlag); + int calcDir(int i, int index); + QGraphicsPixmapItem* occupyTile(int index, uint8_t tileId); + uint8_t m_selected_tile_id; + std::string m_name; + bool m_advanced_tile_placement; + int m_width; + int m_height; + std::vector<uint8_t> m_tile_ids; + std::vector<QGraphicsPixmapItem*> m_tile_occupants; + std::string m_file_path; }; } // namespace editor \ No newline at end of file diff --git a/src/editor/LevelView.cpp b/src/editor/LevelView.cpp index f03243bad5157524df7ac07edfd14f8b6e03089f..2440350e08bea9d9ad5dbb28d1c57503aab9724f 100644 --- a/src/editor/LevelView.cpp +++ b/src/editor/LevelView.cpp @@ -1,9 +1,9 @@ /** -* LevelView.cpp -* -* @date 02.02.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * LevelView.cpp + * + * @date 02.02.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "LevelView.hpp" @@ -12,26 +12,26 @@ namespace editor { -LevelView::LevelView(LevelScene* scene, QWidget* parent) : QGraphicsView(parent), scale_val(2) -{ +LevelView::LevelView(LevelScene* scene, QWidget* parent) : QGraphicsView(parent), m_scaleVal(2) +{ scene->setParent(this); setScene(scene); setAlignment(Qt::AlignCenter); - scale(scale_val, scale_val); // view starts at 2x zoom by default - setBackgroundBrush(QBrush(SpriteProvider::get_sprite(1))); + scale(m_scaleVal, m_scaleVal); // view starts at 2x zoom by default + setBackgroundBrush(QBrush(SpriteProvider::getSprite(1))); } void LevelView::onZoomed(double delta) { - // amount by which to scale has to be calculated using scale_vale (how much was already zoomed before) - // and delta (desired zoom percentage) - double scale_by = (scale_val + delta) / scale_val; - if (scale_by <= 0) + // amount by which to scale has to be calculated using scale_vale (how much was already zoomed + // before) and delta (desired zoom percentage) + double scaleBy = (m_scaleVal + delta) / m_scaleVal; + if (scaleBy <= 0) { return; } - scale_val += delta; - scale(scale_by, scale_by); + m_scaleVal += delta; + scale(scaleBy, scaleBy); } } // namespace editor \ No newline at end of file diff --git a/src/editor/LevelView.hpp b/src/editor/LevelView.hpp index 13d4bea0e6cd73d22bda3ac2f98103fbd38bed8a..88018274601c693f5d835fc8f48c0b2983db85ca 100644 --- a/src/editor/LevelView.hpp +++ b/src/editor/LevelView.hpp @@ -1,45 +1,47 @@ /** -* LevelView.hpp -* -* @date 02.02.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * LevelView.hpp + * + * @date 02.02.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #pragma once #include <QGraphicsView> -#include "LevelScene.hpp" #include "EventHandler.hpp" +#include "LevelScene.hpp" namespace editor { /** * The LevelView Widget is responsible for holding the LevelScene. - * It enables scrolling by default in case the LevelScene does not fit on + * It enables scrolling by default in case the LevelScene does not fit on * the entire screen. * It's also responsible for zooming the LevelScene in case a Zoom Event is received. * To receive Zoom Events LevelView inherits from EventHandler and overwrites onZoomed */ -class LevelView : public QGraphicsView, public EventHandler{ -public: - /** - * Constructs a LevelView widget from the given scene and parent. - * @param scene The level scene that should be contained in this view. - * @param parent The widget to set as this widget's parent. - */ - LevelView(LevelScene* scene, QWidget* parent = nullptr); -private: - /** - * The current value by which the contained scene is scaled up or down. - * E.g 2.0 => twice the size, 0.5 => half the size - */ - double scale_val; - /** - * Zoom by the specified delta. - */ - void onZoomed(double delta) override; +class LevelView : public QGraphicsView, public EventHandler +{ + public: + /** + * Constructs a LevelView widget from the given scene and parent. + * @param scene The level scene that should be contained in this view. + * @param parent The widget to set as this widget's parent. + */ + LevelView(LevelScene* scene, QWidget* parent = nullptr); + + private: + /** + * The current value by which the contained scene is scaled up or down. + * E.g 2.0 => twice the size, 0.5 => half the size + */ + double m_scaleVal; + /** + * Zoom by the specified delta. + */ + void onZoomed(double delta) override; }; } // namespace editor \ No newline at end of file diff --git a/src/editor/MainWindow.cpp b/src/editor/MainWindow.cpp index 8de2390167e39f4508334660ab07d0164d7f01f6..7bc7043429eea18cd2aa7108b18658c0710f7045 100644 --- a/src/editor/MainWindow.cpp +++ b/src/editor/MainWindow.cpp @@ -1,9 +1,9 @@ /** -* MainWindow.cpp -* -* @date 27.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * MainWindow.cpp + * + * @date 27.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "MainWindow.hpp" @@ -17,38 +17,37 @@ #include "TileSelector.hpp" #include "TopBar.hpp" - namespace editor { MainWindow::MainWindow(LevelScene* level, QWidget* parent) - : QMainWindow(parent), m_level_width(level->getWidth()), level_height(level->getHeight()) + : QMainWindow(parent), m_levelWidth(level->getWidth()), m_levelHeight(level->getHeight()) { // CREATE MAIN WINDOW ------------------------------------------ QWidget* mainWidget = new QWidget(this); addToolBar(new TopBar(level->getName(), this)); // CREATE TOOLBOX----------------------------------------------- - TileSelector* tile_selector = new TileSelector(mainWidget); + auto* tileSelector = new TileSelector(mainWidget); // CREATE LEVELMAP - LevelView* level_map = new LevelView(level, this); - level->setParent(level_map); // allow Qt to handle the memory + auto* levelMap = new LevelView(level, this); + level->setParent(levelMap); // allow Qt to handle the memory // LAYOUT------------------------------------------------------- QHBoxLayout* layout = new QHBoxLayout(mainWidget); - layout->addWidget(level_map); - layout->addWidget(tile_selector); + layout->addWidget(levelMap); + layout->addWidget(tileSelector); setCentralWidget(mainWidget); onLevelNameUpdated(level->getName()); } -void MainWindow::onLevelNameUpdated(std::string new_name) +void MainWindow::onLevelNameUpdated(std::string newName) { - std::string dim_text = - "(" + std::to_string(m_level_width) + " X " + std::to_string(level_height) + ")"; - setWindowTitle((new_name + " " + dim_text).c_str()); + std::string dimText = + "(" + std::to_string(m_levelWidth) + " X " + std::to_string(m_levelHeight) + ")"; + setWindowTitle((newName + " " + dimText).c_str()); } } // namespace editor \ No newline at end of file diff --git a/src/editor/MainWindow.hpp b/src/editor/MainWindow.hpp index 8f1844bf35a5bbb1f16cb083ab2b713f65ad0c3e..dea2a5587d6572ba87b9ed50c432ed1bc4f27878 100644 --- a/src/editor/MainWindow.hpp +++ b/src/editor/MainWindow.hpp @@ -1,27 +1,29 @@ /** -* MainWindow.hpp -* -* @date 27.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * MainWindow.hpp + * + * @date 27.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #pragma once #include <QMainWindow> -#include "LevelScene.hpp" #include "EventHandler.hpp" +#include "LevelScene.hpp" + +namespace editor +{ -namespace editor +class MainWindow : public QMainWindow, public EventHandler { + public: + MainWindow(LevelScene* level, QWidget* parent = nullptr); -class MainWindow : public QMainWindow, public EventHandler { -public: - MainWindow(LevelScene* level, QWidget *parent = nullptr); -private: - void onLevelNameUpdated(std::string new_name) override; - int m_level_width; - int level_height; + private: + void onLevelNameUpdated(std::string newName) override; + int m_levelWidth; + int m_levelHeight; }; } // namespace editor \ No newline at end of file diff --git a/src/editor/SaveButton.cpp b/src/editor/SaveButton.cpp index 9f13aa9922fbd2263ee142d130d6bfd291f52173..dc94c84d4ba64523e29f83ec3db005ccfc6bff1e 100644 --- a/src/editor/SaveButton.cpp +++ b/src/editor/SaveButton.cpp @@ -1,9 +1,9 @@ /** -* SaveButton.cpp -* -* @date 29.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * SaveButton.cpp + * + * @date 29.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "SaveButton.hpp" @@ -22,11 +22,11 @@ SaveButton::SaveButton(const std::string& title, QWidget* parent) void SaveButton::mousePressEvent(QMouseEvent* event) { QPushButton::mousePressEvent(event); - QString file_path = QFileDialog::getSaveFileName( + QString filePath = QFileDialog::getSaveFileName( this, "Level Speichern", QDir::currentPath(), "HDF5 Files (*.h5)"); - if (!file_path.isEmpty()) + if (!filePath.isEmpty()) { - EventHandler::send([file_path](EventHandler* e) { e->onLevelWriteRequested(file_path); }); + EventHandler::send([filePath](EventHandler* e) { e->onLevelWriteRequested(filePath); }); } } diff --git a/src/editor/SpriteProvider.cpp b/src/editor/SpriteProvider.cpp index 0bd10dad8b3448abe207b92923862f81130f8532..a9824fafe98be85aa33227935b573a09f3ff07bb 100644 --- a/src/editor/SpriteProvider.cpp +++ b/src/editor/SpriteProvider.cpp @@ -1,13 +1,12 @@ /** -* SpriteProvider.cpp -* -* @date 27.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * SpriteProvider.cpp + * + * @date 27.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "SpriteProvider.hpp" -#include <iostream> #include <stdexcept> namespace editor @@ -15,7 +14,7 @@ namespace editor std::vector<QPixmap> SpriteProvider::sprites = std::vector<QPixmap>(); -QPixmap SpriteProvider::get_sprite(uint8_t id) +QPixmap SpriteProvider::getSprite(uint8_t id) { if (sprites.empty()) { @@ -41,26 +40,27 @@ void SpriteProvider::initialize(const std::string& path) sprites.reserve(60); // we now that we will load 60 sprites // load terrains - for (size_t i = 0; i < tile_names.size(); i++) + for (size_t i = 0; i < TILE_NAMES.size(); i++) { // size_t? std::vector<std::vector<std::vector<uint32_t>>> pixels; - file.getDataSet("tiles/" + tile_names[i]).read(pixels); - sprites.push_back(SpriteProvider::load_pixmap(pixels, 0)); + file.getDataSet("tiles/" + TILE_NAMES[i]).read(pixels); + sprites.push_back(SpriteProvider::loadPixmap(pixels, 0)); } // load buildings - for (const std::string& faction_name : faction_names) + for (const std::string& factionName : FACTION_NAMES) { std::vector<std::vector<std::vector<uint32_t>>> pixels; - file.getDataSet("buildings/" + faction_name).read(pixels); + file.getDataSet("buildings/" + factionName).read(pixels); for (int i = 0; i < 5; i++) { - sprites.push_back(SpriteProvider::load_pixmap(pixels, i)); + sprites.push_back(SpriteProvider::loadPixmap(pixels, i)); } } } -QPixmap SpriteProvider::load_pixmap(std::vector<std::vector<std::vector<uint32_t>>> pixels, int index) +QPixmap +SpriteProvider::loadPixmap(std::vector<std::vector<std::vector<uint32_t>>> pixels, int index) { int width = pixels[index][0].size(); int height = pixels[index].size(); diff --git a/src/editor/SpriteProvider.hpp b/src/editor/SpriteProvider.hpp index 35ebe316d50e40f559b26c293328318d942a140e..6b8cfb1b6901ae79194372707d1acfaf625d4959 100644 --- a/src/editor/SpriteProvider.hpp +++ b/src/editor/SpriteProvider.hpp @@ -1,9 +1,9 @@ /** -* SpriteProvider.hpp -* -* @date 27.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * SpriteProvider.hpp + * + * @date 27.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #pragma once @@ -17,91 +17,94 @@ namespace editor /** * Provides all tile names. - * They are necessary to create the correct path to + * They are necessary to create the correct path to * the hdf5 dataset that contains the pixels for a given tile. */ -const std::vector<std::string> tile_names({"plain", - "water", - "forest", - "mountain", - "bridge_horizontal", - "bridge_vertical", - "street_horizontal", - "street_vertical", - "street_crossing", - "street_junction_right", - "street_junction_left", - "street_junction_down", - "street_junction_up", - "street_corner_top_left", - "street_corner_top_right", - "street_corner_bottom_left", - "street_corner_bottom_right", - "riff", - "cliff_top", - "cliff_bottom", - "cliff_left", - "cliff_right", - "cliff_corner_top_left", - "cliff_corner_top_right", - "cliff_corner_bottom_left", - "cliff_corner_bottom_right", - "cliff_inverse_corner_top_left", - "cliff_inverse_corner_top_right", - "cliff_inverse_corner_bottom_left", - "cliff_inverse_corner_bottom_right"}); +const std::vector<std::string> TILE_NAMES( + {"plain", + "water", + "forest", + "mountain", + "bridge_horizontal", + "bridge_vertical", + "street_horizontal", + "street_vertical", + "street_crossing", + "street_junction_right", + "street_junction_left", + "street_junction_down", + "street_junction_up", + "street_corner_top_left", + "street_corner_top_right", + "street_corner_bottom_left", + "street_corner_bottom_right", + "riff", + "cliff_top", + "cliff_bottom", + "cliff_left", + "cliff_right", + "cliff_corner_top_left", + "cliff_corner_top_right", + "cliff_corner_bottom_left", + "cliff_corner_bottom_right", + "cliff_inverse_corner_top_left", + "cliff_inverse_corner_top_right", + "cliff_inverse_corner_bottom_left", + "cliff_inverse_corner_bottom_right"}); /** * Provides the names for all factions in the game. * The names can be used to create the path to the hdf5 dataset * containing the buildings for a given faction. */ -const std::vector<std::string> faction_names( - {"red", "blue", "yellow", "green", "purple", "neutral"}); +const std::vector<std::string> + FACTION_NAMES({"red", "blue", "yellow", "green", "purple", "neutral"}); /** * SpriteProvider is only used in a static context. * SpriteProvider allows us to get the QPixmap for a given tile type - * from anywhere in the program using SpriteProvider::get_sprite(id); + * from anywhere in the program using SpriteProvider::getSprite(id); * When SpriteProvider is initialized, it loads all the Sprites from the hdf5 Spritesheet * and stores them in the static sprites variable. * From then on, fast access to any sprite as a QPixmap is possible. */ -class SpriteProvider { -public: - /** - * SpriteProvider is only used in a static context - */ - SpriteProvider() = delete; - /** - * Allows you to retrieve the QPixmap of any tile given its id. - * @param id The id of the tile type whose sprite you want to get. - * @return The QPixmap for the provided tile id. - */ - static QPixmap get_sprite(uint8_t id); - /** - * Always call initialize at the start of the program, to load - * all of the sprites from the Spritesheet under the provided path. - * Stores all sprites of the provided Spritesheet for later quick retrieval. - * @param path The path to the hdf5 spritesheet - */ - static void initialize(const std::string& path); +class SpriteProvider +{ + public: + /** + * SpriteProvider is only used in a static context + */ + SpriteProvider() = delete; + /** + * Allows you to retrieve the QPixmap of any tile given its id. + * @param id The id of the tile type whose sprite you want to get. + * @return The QPixmap for the provided tile id. + */ + static QPixmap getSprite(uint8_t id); + /** + * Always call initialize at the start of the program, to load + * all of the sprites from the Spritesheet under the provided path. + * Stores all sprites of the provided Spritesheet for later quick retrieval. + * @param path The path to the hdf5 spritesheet + */ + static void initialize(const std::string& path); -private: - /** - * Creates a QPixmap from the given pixels. - * The provided 3-dim pixels vector contains multiple sprites, which is where the third dimension - * comes from. - * With the index you can control which sprite from the pixels Vector to create. - * @param pixels The 3-dim vector of pixel values. - * @param index The index of the pixeldata in the 3-dim Vector to use. - * @return The QPixmap object that was created from the provided pixels. - */ - static QPixmap load_pixmap(std::vector<std::vector<std::vector<uint32_t>>> pixels, int index); - /** - * Holds all of the game's sprites for quick access. - */ - static std::vector<QPixmap> sprites; + private: + /** + * Creates a QPixmap from the given pixels. + * The provided 3-dim pixels vector contains multiple sprites, which is where the third + * dimension comes from. With the index you can control which sprite from the pixels Vector + * to create. + * @param pixels The 3-dim vector of pixel values. + * @param index The index of the pixeldata in the 3-dim Vector to use. + * @return The QPixmap object that was created from the provided pixels. + */ + static QPixmap + loadPixmap(std::vector<std::vector<std::vector<uint32_t>>> pixels, int index); + /** + * Holds all of the game's sprites for quick access. + */ + static std::vector<QPixmap> sprites; }; } // namespace editor \ No newline at end of file diff --git a/src/editor/Tile.cpp b/src/editor/Tile.cpp index bf332674ed7a7cdb6f9598b9109f253765363830..5eba161617283ab1f7a43b398def930de52ec06f 100644 --- a/src/editor/Tile.cpp +++ b/src/editor/Tile.cpp @@ -1,9 +1,9 @@ /** -* Tile.cpp -* -* @date 27.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * Tile.cpp + * + * @date 27.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "Tile.hpp" @@ -13,24 +13,25 @@ namespace editor { -Tile::Tile(int index, uint8_t id) : QGraphicsPixmapItem(SpriteProvider::get_sprite(id)), m_index(index) +Tile::Tile(int index, uint8_t id) + : QGraphicsPixmapItem(SpriteProvider::getSprite(id)), m_index(index) { this->setAcceptHoverEvents(true); } -void Tile::hoverEnterEvent(QGraphicsSceneHoverEvent* event) +void Tile::hoverEnterEvent(QGraphicsSceneHoverEvent* /*event*/) { int index = this->m_index; EventHandler::send([index](EventHandler* e) { e->onTileEntered(index); }); } -void Tile::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) +void Tile::hoverLeaveEvent(QGraphicsSceneHoverEvent* /*event*/) { int index = this->m_index; EventHandler::send([index](EventHandler* e) { e->onTileExited(index); }); } -void Tile::mousePressEvent(QGraphicsSceneMouseEvent* event) +void Tile::mousePressEvent(QGraphicsSceneMouseEvent* /*event*/) { int index = this->m_index; EventHandler::send([index](EventHandler* e) { e->onTileClicked(index); }); diff --git a/src/editor/TileButton.cpp b/src/editor/TileButton.cpp index b302955ef81c38a8b67cf0e1b9e817453c3a3ee2..731c6172cf5fed3e1680074e8d6a3a28d733115e 100644 --- a/src/editor/TileButton.cpp +++ b/src/editor/TileButton.cpp @@ -1,10 +1,10 @@ /** -* TileSelector.cpp -* -* @date 29.01.2025 -* @author Nils Jonathan Friedrich Eckardt implementation -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) minor changes -*/ + * TileSelector.cpp + * + * @date 29.01.2025 + * @author Nils Jonathan Friedrich Eckardt implementation + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) minor changes + */ #include "TileButton.hpp" @@ -16,7 +16,7 @@ namespace editor TileButton::TileButton(const uint8_t id, QWidget* parent) : QPushButton(parent), m_id(id) { - QPixmap pixmap = SpriteProvider::get_sprite(id); + QPixmap pixmap = SpriteProvider::getSprite(id); QPixmap scaledpixmap = pixmap.scaled(72, 72, Qt::KeepAspectRatio, Qt::FastTransformation); this->setIcon(QIcon(scaledpixmap)); this->setIconSize(QSize(72, 72)); @@ -26,8 +26,8 @@ TileButton::TileButton(const uint8_t id, QWidget* parent) : QPushButton(parent), void TileButton::mousePressEvent(QMouseEvent* event) { QPushButton::mousePressEvent(event); - uint8_t tile_id = m_id; - EventHandler::send([tile_id](EventHandler* e) { e->onNewTileIdSelected(tile_id); }); + uint8_t tileId = m_id; + EventHandler::send([tileId](EventHandler* e) { e->onNewTileIdSelected(tileId); }); } } // namespace editor \ No newline at end of file diff --git a/src/editor/TileSelector.cpp b/src/editor/TileSelector.cpp index 1a0877e635510c1ed57fc4814b20e65422a45d60..1dcbe7bc7bbeb82cb15f5ca7f0a17c9142abcbbb 100644 --- a/src/editor/TileSelector.cpp +++ b/src/editor/TileSelector.cpp @@ -1,10 +1,10 @@ /** -* TileSelector.cpp -* -* @date 28.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) skeleton -* @author Nils Jonathan Friedrich Eckardt implementation -*/ + * TileSelector.cpp + * + * @date 28.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) skeleton + * @author Nils Jonathan Friedrich Eckardt implementation + */ #include "TileSelector.hpp" @@ -13,10 +13,8 @@ #include <QPushButton> #include <QVBoxLayout> -#include "SpriteProvider.hpp" #include "TileButton.hpp" - namespace editor { diff --git a/src/editor/TileSelector.hpp b/src/editor/TileSelector.hpp index 5abd400c4964daadf5a59d626b7ff10c9cafa7ba..8a0d077345d3c02008439024af968346da271cd9 100644 --- a/src/editor/TileSelector.hpp +++ b/src/editor/TileSelector.hpp @@ -1,36 +1,36 @@ /** -* TileSelector.cpp -* -* @date 28.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) skeleton -* @author Nils Jonathan Friedrich Eckardt implementation -*/ + * TileSelector.cpp + * + * @date 28.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) skeleton + * @author Nils Jonathan Friedrich Eckardt implementation + */ #pragma once -#include <QScrollArea> +#include <QGridLayout> #include <QLabel> #include <QPushButton> -#include <QGridLayout> - -#include "SpriteProvider.hpp" +#include <QScrollArea> namespace editor { -class TileSelector : public QScrollArea { -public: - TileSelector(QWidget *parent = nullptr); - -private: - QLabel *createNewLabel(QWidget* parent, const char *text); +class TileSelector : public QScrollArea +{ + public: + TileSelector(QWidget* parent = nullptr); + + private: + QLabel* createNewLabel(QWidget* parent, const char* text); - template<typename T> - void sectionLayout(QGridLayout*& layout, int usedIdCounter, QWidget* parent, T id); - template<typename T, typename... Rest> - void sectionLayout(QGridLayout*& layout, int usedIdCounter, QWidget* parent, T id, Rest...ids); - template<typename... T> - QGridLayout* creatSectionLayout(QWidget* parent, T... ids); + template <typename T> + void sectionLayout(QGridLayout*& layout, int usedIdCounter, QWidget* parent, T id); + template <typename T, typename... Rest> + void + sectionLayout(QGridLayout*& layout, int usedIdCounter, QWidget* parent, T id, Rest... ids); + template <typename... T> + QGridLayout* creatSectionLayout(QWidget* parent, T... ids); }; } // namespace editor \ No newline at end of file diff --git a/src/editor/TopBar.cpp b/src/editor/TopBar.cpp index 5e5f52c547ea5a40aee910b773ad5b98d0c90bb5..5637b45b2b684bfb87fbf13bfe50e4c31a4d2795 100644 --- a/src/editor/TopBar.cpp +++ b/src/editor/TopBar.cpp @@ -1,10 +1,10 @@ /** -* TopBar.cpp -* -* @date 28.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -* @author Nils Jonathan Friedrich Eckardt minor change -*/ + * TopBar.cpp + * + * @date 28.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + * @author Nils Jonathan Friedrich Eckardt minor change + */ #include "TopBar.hpp" @@ -12,48 +12,48 @@ #include <QLabel> #include <QSize> +#include "AutomateButton.hpp" #include "LevelNameEdit.hpp" #include "SaveButton.hpp" #include "ZoomInButton.hpp" #include "ZoomInfo.hpp" #include "ZoomOutButton.hpp" -#include "AutomateButton.hpp" namespace editor { -TopBar::TopBar(const std::string& level_name, QWidget* parent) : QToolBar(parent) +TopBar::TopBar(const std::string& levelName, QWidget* parent) : QToolBar(parent) { - QWidget* container = new QWidget(this); - QHBoxLayout* main_layout = new QHBoxLayout(container); - QWidget* left_container = new QWidget(container); - QWidget* right_container = new QWidget(container); - QHBoxLayout* left_layout = new QHBoxLayout(left_container); - QHBoxLayout* right_layout = new QHBoxLayout(right_container); - - QLabel* field_label = new QLabel("Name: ", left_container); - LevelNameEdit* text_field = new LevelNameEdit(level_name, left_container); - left_layout->addWidget(field_label); - left_layout->addWidget(text_field); - left_layout->addStretch(); - - QPushButton* save_button = new SaveButton("Speichern", right_container); - QPushButton* zoom_in = new ZoomInButton(right_container); - QPushButton* zoom_out = new ZoomOutButton(right_container); - QPushButton* zoom_info = new ZoomInfo(right_container); - AutomateButton* checkedBox = new AutomateButton("Kacheln automatisch setzen", container); - left_layout->addWidget(checkedBox); - right_layout->addStretch(); - right_layout->addWidget(zoom_out); - right_layout->addWidget(zoom_info); - right_layout->addWidget(zoom_in); - right_layout->addStretch(); - right_layout->addWidget(save_button); - right_layout->addStretch(); - - right_container->setFixedWidth(300); - main_layout->addWidget(left_container, 1); - main_layout->addWidget(right_container); + QWidget* container = new QWidget(this); + auto* mainLayout = new QHBoxLayout(container); + auto* leftContainer = new QWidget(container); + auto* rightContainer = new QWidget(container); + auto* leftLayout = new QHBoxLayout(leftContainer); + auto* rightLayout = new QHBoxLayout(rightContainer); + + auto* fieldLabel = new QLabel("Name: ", leftContainer); + auto* textField = new LevelNameEdit(levelName, leftContainer); + leftLayout->addWidget(fieldLabel); + leftLayout->addWidget(textField); + leftLayout->addStretch(); + + QPushButton* saveButton = new SaveButton("Speichern", rightContainer); + QPushButton* zoomIn = new ZoomInButton(rightContainer); + QPushButton* zoomOut = new ZoomOutButton(rightContainer); + QPushButton* zoomInfo = new ZoomInfo(rightContainer); + auto* checkedBox = new AutomateButton("Kacheln automatisch setzen", container); + leftLayout->addWidget(checkedBox); + rightLayout->addStretch(); + rightLayout->addWidget(zoomOut); + rightLayout->addWidget(zoomInfo); + rightLayout->addWidget(zoomIn); + rightLayout->addStretch(); + rightLayout->addWidget(saveButton); + rightLayout->addStretch(); + + rightContainer->setFixedWidth(300); + mainLayout->addWidget(leftContainer, 1); + mainLayout->addWidget(rightContainer); this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); // Allow resizing this->addWidget(container); diff --git a/src/editor/TopBar.hpp b/src/editor/TopBar.hpp index a65f453fe038c2954459f9aff72d3d125fb566df..6f97a49fd9a42755efd6fc4476f2e8a2805f638e 100644 --- a/src/editor/TopBar.hpp +++ b/src/editor/TopBar.hpp @@ -1,9 +1,9 @@ /** -* TopBar.hpp -* -* @date 28.01.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * TopBar.hpp + * + * @date 28.01.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #pragma once @@ -12,9 +12,10 @@ namespace editor { -class TopBar : public QToolBar { -public: - TopBar(const std::string& level_name, QWidget *parent = nullptr); +class TopBar : public QToolBar +{ + public: + TopBar(const std::string& levelName, QWidget* parent = nullptr); }; } // namespace editor \ No newline at end of file diff --git a/src/editor/ZoomInButton.cpp b/src/editor/ZoomInButton.cpp index 3f15b7914a43a31dbd8ff97d6123ce3e019d5145..68b442262265cd3831fff7b18c42f0259c096571 100644 --- a/src/editor/ZoomInButton.cpp +++ b/src/editor/ZoomInButton.cpp @@ -1,9 +1,9 @@ /** -* ZoomInButton.cpp -* -* @date 02.02.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * ZoomInButton.cpp + * + * @date 02.02.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "ZoomInButton.hpp" @@ -17,7 +17,7 @@ ZoomInButton::ZoomInButton(QWidget* parent) : QPushButton("+", parent) setFixedWidth(20); } -void ZoomInButton::mousePressEvent(QMouseEvent* event) +void ZoomInButton::mousePressEvent(QMouseEvent* /*event*/) { EventHandler::send([](EventHandler* e) { e->onZoomed(0.25); }); } diff --git a/src/editor/ZoomInfo.cpp b/src/editor/ZoomInfo.cpp index 3ec241306b953f2b183cb1116a34b210f15860ab..fd435e8868127cdc66602c72d4416d918a4eae4a 100644 --- a/src/editor/ZoomInfo.cpp +++ b/src/editor/ZoomInfo.cpp @@ -1,28 +1,30 @@ /** -* ZoomInfo.hpp -* -* @date 02.02.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * ZoomInfo.hpp + * + * @date 02.02.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "ZoomInfo.hpp" namespace editor { -ZoomInfo::ZoomInfo(QWidget* parent) : QPushButton(parent), current_scale(2) +ZoomInfo::ZoomInfo(QWidget* parent) : QPushButton(parent), m_currentScale(2) { setDisabled(true); - setText((std::to_string((int)std::round(current_scale * 100)) + "%").c_str()); + setText((std::to_string((int)std::round(m_currentScale * 100)) + "%").c_str()); setFixedWidth(50); } void ZoomInfo::onZoomed(double delta) { - if (current_scale + delta <= 0) + if (m_currentScale + delta <= 0) + { return; - current_scale += delta; - setText((std::to_string((int)std::round(current_scale * 100)) + " %").c_str()); + } + m_currentScale += delta; + setText((std::to_string((int)std::round(m_currentScale * 100)) + " %").c_str()); } } // namespace editor \ No newline at end of file diff --git a/src/editor/ZoomInfo.hpp b/src/editor/ZoomInfo.hpp index f539182742da8dcdf4804aae6972aca1612f2206..ad5a3e86186a8af9976a71313d44a7385aba7272 100644 --- a/src/editor/ZoomInfo.hpp +++ b/src/editor/ZoomInfo.hpp @@ -1,9 +1,9 @@ /** -* ZoomInfo.cpp -* -* @date 02.02.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * ZoomInfo.cpp + * + * @date 02.02.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #pragma once @@ -14,12 +14,14 @@ namespace editor { -class ZoomInfo : public QPushButton, public EventHandler { -public: - ZoomInfo(QWidget* parent = nullptr); -private: - double current_scale; - void onZoomed(double delta) override; +class ZoomInfo : public QPushButton, public EventHandler +{ + public: + ZoomInfo(QWidget* parent = nullptr); + + private: + double m_currentScale; + void onZoomed(double delta) override; }; } // namespace editor \ No newline at end of file diff --git a/src/editor/ZoomOutButton.cpp b/src/editor/ZoomOutButton.cpp index aec5b3260299f01aee1be48241d054676c05f599..17aeb967a2be8aa133aae556ece47523a5bdcf99 100644 --- a/src/editor/ZoomOutButton.cpp +++ b/src/editor/ZoomOutButton.cpp @@ -1,9 +1,9 @@ /** -* ZoomOutButton.cpp -* -* @date 02.02.2025 -* @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) -*/ + * ZoomOutButton.cpp + * + * @date 02.02.2025 + * @author Jonathan Dueck (jonathan.dueck@informatik.hs-fulda.de) + */ #include "ZoomOutButton.hpp" @@ -17,7 +17,7 @@ ZoomOutButton::ZoomOutButton(QWidget* parent) : QPushButton("-", parent) setFixedWidth(20); } -void ZoomOutButton::mousePressEvent(QMouseEvent* event) +void ZoomOutButton::mousePressEvent(QMouseEvent* /*event*/) { EventHandler::send([](EventHandler* e) { e->onZoomed(-0.25); }); } diff --git a/src/editor/main.cpp b/src/editor/main.cpp index 9831c25bcc06721b76d3faee2bd240a8f22378f2..d845619992526d555d917c44c879ccd566a57b84 100644 --- a/src/editor/main.cpp +++ b/src/editor/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char* argv[]) // to get the QGraphicsPixmap for a specific tile. SpriteProvider::initialize("../res/spritesheet.h5"); - LevelScene* level; + LevelScene* level = nullptr; if (argc == 2) { // 1 argument provided => create Level from file level = LevelScene::fromFile(argv[1]); diff --git a/src/game/combat/CombatEngine.cpp b/src/game/combat/CombatEngine.cpp index 8f5323b6319562d4a61e5af762ee950f3eaa7ed2..3c0b1e3aef26556eba5dcecb685b306404c7479e 100644 --- a/src/game/combat/CombatEngine.cpp +++ b/src/game/combat/CombatEngine.cpp @@ -137,25 +137,25 @@ CombatEngine::getUnitsInRangeWithDamagePotential(Unit& attacker, std::vector<Uni return unitsInRangeWithDamage; } -void CombatEngine::handleAttackingEvents(Engine& engine, SDL_Event& event, Level& m_level) +void CombatEngine::handleAttackingEvents(Engine& engine, SDL_Event& event, Level& level) { - if (m_level.getAttackableUnitIds().empty()) + if (level.getAttackableUnitIds().empty()) { std::cout << "No units are within attack range." << "\n"; - m_level.setState(LevelState::MENUACTIVE_STATE); + level.setState(LevelState::MENUACTIVE_STATE); return; // Early exit if no units to attack } switch (event.type) { case SDL_KEYDOWN: - m_level.handlePositionMarker(engine, event); + level.handlePositionMarker(engine, event); if (event.key.keysym.sym == SDLK_ESCAPE) { - m_level.setState(LevelState::MENUACTIVE_STATE); + level.setState(LevelState::MENUACTIVE_STATE); } if (event.key.keysym.sym == SDLK_RETURN) { - handleAttack(m_level.getTilemarker().getPosition(), m_level); + handleAttack(level.getTilemarker().getPosition(), level); } break; default: @@ -163,15 +163,14 @@ void CombatEngine::handleAttackingEvents(Engine& engine, SDL_Event& event, Level } } -void CombatEngine::handleAttack(std::pair<int, int> tilePos, Level& m_level) +void CombatEngine::handleAttack(std::pair<int, int> tilePos, Level& level) { - std::unordered_map<int, std::unique_ptr<Unit>>& units = m_level.getUnits(); - int selectedUnit = m_level.getSelectedUnit(); - int targetedUnit = m_level.selectUnit(tilePos.first, tilePos.second); + std::unordered_map<int, std::unique_ptr<Unit>>& units = level.getUnits(); + int selectedUnit = level.getSelectedUnit(); + int targetedUnit = level.selectUnit(tilePos.first, tilePos.second); if (targetedUnit >= 0) { - if (units.at(m_level.getSelectedUnit())->getFaction() == - units.at(targetedUnit)->getFaction()) + if (units.at(level.getSelectedUnit())->getFaction() == units.at(targetedUnit)->getFaction()) { std::cout << "You cannot attack your allies!" << "\n"; return; @@ -188,7 +187,7 @@ void CombatEngine::handleAttack(std::pair<int, int> tilePos, Level& m_level) std::unique_ptr<Unit>& attacking = itAttacker->second; std::unique_ptr<Unit>& defending = itDefender->second; - std::unordered_set<int>& attackableUnitIds = m_level.getAttackableUnitIds(); + std::unordered_set<int>& attackableUnitIds = level.getAttackableUnitIds(); if (attackableUnitIds.find(targetedUnit) != attackableUnitIds.end()) { attack(*attacking, *defending); @@ -196,7 +195,7 @@ void CombatEngine::handleAttack(std::pair<int, int> tilePos, Level& m_level) // attacking->attack(defending); if (attacking->getHealth() <= 0) { - m_level.removeUnit(selectedUnit); + level.removeUnit(selectedUnit); } else { @@ -204,12 +203,12 @@ void CombatEngine::handleAttack(std::pair<int, int> tilePos, Level& m_level) } if (defending->getHealth() <= 0) { - m_level.removeUnit(targetedUnit); + level.removeUnit(targetedUnit); } - m_level.setSelectedUnit(-1); - m_level.setShowAttackableTiles(false); - m_level.setShowReachableTiles(false); - m_level.setState(LevelState::SELECTING_STATE); + level.setSelectedUnit(-1); + level.setShowAttackableTiles(false); + level.setShowReachableTiles(false); + level.setState(LevelState::SELECTING_STATE); } else { diff --git a/src/game/combat/CombatEngine.hpp b/src/game/combat/CombatEngine.hpp index 4b26f1a0c6ccc4e1cbc9b93164f5ef57e1599774..4e3ef02f9918356fa722e4fe714a74dd01d91c94 100644 --- a/src/game/combat/CombatEngine.hpp +++ b/src/game/combat/CombatEngine.hpp @@ -14,8 +14,8 @@ class CombatEngine CombatEngine(); ~CombatEngine() = default; - void handleAttackingEvents(Engine& engine, SDL_Event& event, Level& m_level); - void handleAttack(std::pair<int, int> tilePos, Level& m_level); + void handleAttackingEvents(Engine& engine, SDL_Event& event, Level& level); + void handleAttack(std::pair<int, int> tilePos, Level& level); static void attack(Unit& attacker, Unit& target); static int calculateDamage(Unit& attacker, Unit& target); static void takeDamage(Unit& attacker, Unit& target, int damage); diff --git a/src/game/combat/Weapon.cpp b/src/game/combat/Weapon.cpp index ce89ef11dd42f230dc5c55a3239e311a7994c052..091c67efa5094495bed781a25a0eb3c3ca8652c4 100644 --- a/src/game/combat/Weapon.cpp +++ b/src/game/combat/Weapon.cpp @@ -2,7 +2,7 @@ namespace advanced_wars { -Weapon::Weapon() : m_name(""), m_damage() {} +Weapon::Weapon() {} Weapon::Weapon( const std::string& weaponName, const std::unordered_map<UnitTypeId, int>& damageValues) diff --git a/src/game/core/Config.cpp b/src/game/core/Config.cpp index 8c5f23c1050ada6d24a90682cf52805e967f8c5e..64a98fee23e73453fca9ec84c5e92dd73f38329a 100644 --- a/src/game/core/Config.cpp +++ b/src/game/core/Config.cpp @@ -21,13 +21,15 @@ Config::Config(std::string filename) for (const auto& unit : tree.get_child("Units")) { if (unit.first != "Unit") + { continue; + } const auto& unitData = unit.second; - std::string unit_key = unitData.get<std::string>("<xmlattr>.key"); + auto unitKey = unitData.get<std::string>("<xmlattr>.key"); try { - UnitTypeId unitId = mapUnitKeyToID(unit_key); + UnitTypeId unitId = mapUnitKeyToID(unitKey); m_unitCosts[unitId] = unitData.get<int>("Cost"); m_unitMovementPoints[unitId] = unitData.get<int>("MovementPoints"); @@ -35,15 +37,15 @@ Config::Config(std::string filename) m_unitMinRange[unitId] = unitData.get<int>("minRange", 0); m_unitMaxRange[unitId] = unitData.get<int>("maxRange", 0); - std::string movement_type_str = unitData.get<std::string>("MovementType"); + auto movementTypeStr = unitData.get<std::string>("MovementType"); try { - m_unitMovementType[unitId] = mapMovementType(movement_type_str); + m_unitMovementType[unitId] = mapMovementType(movementTypeStr); } catch (const std::out_of_range& e) { - std::cerr << "Unknown movement type: " << movement_type_str - << " for unit key: " << unit_key << "\n"; + std::cerr << "Unknown movement type: " << movementTypeStr + << " for unit key: " << unitKey << "\n"; continue; } @@ -56,10 +58,12 @@ Config::Config(std::string filename) for (const auto& damage : weapon.second.get_child("DamageTable")) { if (damage.first != "Damage") + { continue; + } - std::string target_key = damage.second.get<std::string>("<xmlattr>.unitId"); - UnitTypeId targetId = mapUnitKeyToID(target_key); + auto targetKey = damage.second.get<std::string>("<xmlattr>.unitId"); + UnitTypeId targetId = mapUnitKeyToID(targetKey); m_primaryWeaponDamage[unitId][targetId] = damage.second.get<int>("<xmlattr>.value"); } @@ -72,10 +76,12 @@ Config::Config(std::string filename) for (const auto& damage : weapon.second.get_child("DamageTable")) { if (damage.first != "Damage") + { continue; + } - std::string target_key = damage.second.get<std::string>("<xmlattr>.unitId"); - UnitTypeId targetId = mapUnitKeyToID(target_key); + auto targetKey = damage.second.get<std::string>("<xmlattr>.unitId"); + UnitTypeId targetId = mapUnitKeyToID(targetKey); m_secondaryWeaponDamage[unitId][targetId] = damage.second.get<int>("<xmlattr>.value"); } @@ -90,9 +96,9 @@ Config::Config(std::string filename) } } -UnitTypeId Config::mapUnitKeyToID(const std::string& unit_key) const +UnitTypeId Config::mapUnitKeyToID(const std::string& unitKey) const { - static const std::unordered_map<std::string, UnitTypeId> unit_map = { + static const std::unordered_map<std::string, UnitTypeId> UNIT_MAP = { { "infantry", UnitTypeId::INFANTERY}, { "mechanized_infantry", UnitTypeId::MECHANIZED_INFANTERY}, { "recon", UnitTypeId::RECON}, @@ -114,17 +120,17 @@ UnitTypeId Config::mapUnitKeyToID(const std::string& unit_key) const { "bomber", UnitTypeId::BOMBER} }; - auto it = unit_map.find(unit_key); - if (it != unit_map.end()) + auto it = UNIT_MAP.find(unitKey); + if (it != UNIT_MAP.end()) { return it->second; } - throw std::out_of_range("Unknown unit key: " + unit_key); + throw std::out_of_range("Unknown unit key: " + unitKey); } MovementType Config::mapMovementType(const std::string& movementTypeStr) const { - static const std::unordered_map<std::string, MovementType> movement_map = { + static const std::unordered_map<std::string, MovementType> MOVEMENT_MAP = { { "Foot", MovementType::FOOT}, {"Wheeled", MovementType::WHEELED}, { "Tread", MovementType::TREAD}, @@ -133,8 +139,8 @@ MovementType Config::mapMovementType(const std::string& movementTypeStr) const { "Lander", MovementType::LANDER} }; - auto it = movement_map.find(movementTypeStr); - if (it != movement_map.end()) + auto it = MOVEMENT_MAP.find(movementTypeStr); + if (it != MOVEMENT_MAP.end()) { return it->second; } diff --git a/src/game/core/Config.hpp b/src/game/core/Config.hpp index f9ba4897f75a26c8d1ab983bd56fb19412ee1b8f..e1743e189a880ff5173d595eb50a1caa59d13127 100644 --- a/src/game/core/Config.hpp +++ b/src/game/core/Config.hpp @@ -203,7 +203,7 @@ class Config * @param unit_key The string key representing a unit type. * @return The corresponding UnitTypeId. */ - UnitTypeId mapUnitKeyToID(const std::string& unit_key) const; + UnitTypeId mapUnitKeyToID(const std::string& unitKey) const; /** * @brief Converts a movement type string from the XML file to its corresponding diff --git a/src/game/core/Engine.cpp b/src/game/core/Engine.cpp index 8f8ab437c50f100084fd1effe2235d1102d35982..52674cb4793c7625acf46c70f9b3ff01b2345e23 100644 --- a/src/game/core/Engine.cpp +++ b/src/game/core/Engine.cpp @@ -19,13 +19,13 @@ namespace advanced_wars { Engine::Engine(Window& window) - : m_window(window), m_quit(false), m_unitConfig("../config.xml"), + : m_window(window), + m_SDLRenderer(SDL_CreateRenderer( + this->m_window.sdlWindow(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)), + m_quit(false), m_stage(0), m_unitConfig("../config.xml"), m_gameManager(std::make_unique<GameManager>()) { - this->m_SDLRenderer = SDL_CreateRenderer( - this->m_window.sdl_window(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (m_SDLRenderer == nullptr) { throw std::runtime_error("SDL could not generate renderer: " + std::string(SDL_GetError())); @@ -72,7 +72,7 @@ void Engine::setSpritesheet(Spritesheet& spritesheet) void Engine::pump() { SDL_Event e; - while (SDL_PollEvent(&e)) + while (SDL_PollEvent(&e) != 0) { if (e.type == SDL_QUIT) { diff --git a/src/game/core/Spritesheet.cpp b/src/game/core/Spritesheet.cpp index 997b7766e8ab83f31ccf8fa7312a0bfb96f0d7e1..65e927bb25f4c46e04c1c5e6962162ab5af49ea1 100644 --- a/src/game/core/Spritesheet.cpp +++ b/src/game/core/Spritesheet.cpp @@ -22,6 +22,7 @@ namespace advanced_wars { Spritesheet::Spritesheet(std::string path, Engine& engine) + : m_tileWidth(16), m_tileHeight(16), m_buildingWidth(16), m_buildingHeight(32) { HighFive::File file(path, HighFive::File::ReadOnly); @@ -60,86 +61,83 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) "cliff_inverse_corner_bottom_right"}); // every sub data set of tiles - for (size_t tile_idx = 0; tile_idx < tiles.size(); tile_idx++) + for (const auto& tile : tiles) { - HighFive::DataSet units_ds = file.getDataSet("tiles/" + tiles[tile_idx]); + HighFive::DataSet unitsDs = file.getDataSet("tiles/" + tile); - std::vector<std::vector<std::vector<uint32_t>>> tile_frames; - units_ds.read(tile_frames); + std::vector<std::vector<std::vector<uint32_t>>> tileFrames; + unitsDs.read(tileFrames); - std::vector<uint32_t> tile_buffer(16 * 16 * tile_frames.size(), 0); + std::vector<uint32_t> tileBuffer(16 * 16 * tileFrames.size(), 0); // every animation frame - for (size_t n = 0; n < tile_frames.size(); n++) + for (size_t n = 0; n < tileFrames.size(); n++) { for (size_t y = 0; y < 16; y++) { for (size_t x = 0; x < 16; x++) { - size_t index = (y * tile_frames.size() * 16) + (n * 16 + x); + size_t index = (y * tileFrames.size() * 16) + (n * 16 + x); - tile_buffer.at(index) = tile_frames.at(n).at(16 - y - 1).at(x); + tileBuffer.at(index) = tileFrames.at(n).at(16 - y - 1).at(x); } } } SDL_Texture* tmp = SDL_CreateTexture( engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, - tile_frames.size() * 16, 16); + tileFrames.size() * 16, 16); SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND); if (tmp == nullptr) { throw std::runtime_error( - "Fehler beim Erstellen der Textur für die Units: " + std::string(SDL_GetError())); + "Fehler beim Erstellen der Textur für die Tiles: " + std::string(SDL_GetError())); } if (SDL_UpdateTexture( - tmp, NULL, tile_buffer.data(), tile_frames.size() * 16 * sizeof(int32_t)) != 0) + tmp, nullptr, tileBuffer.data(), tileFrames.size() * 16 * sizeof(int32_t)) != 0) { throw std::runtime_error( - "Fehler beim updaten der Textur für die Units: " + std::string(SDL_GetError())); + "Fehler beim updaten der Textur für die Tiles: " + std::string(SDL_GetError())); } - m_tileTextures.push_back(std::pair<SDL_Texture*, int>(tmp, tile_frames.size())); + m_tileTextures.emplace_back(tmp, tileFrames.size()); } - this->m_tileWidth = 16; - this->m_tileHeight = 16; - // Buildings - std::vector<std::string> building_factions( + std::vector<std::string> buildingFactions( {"red", "blue", "green", "yellow", "purple", "neutral"}); // every sub data set of buildings - for (std::string faction : building_factions) + for (const std::string& faction : buildingFactions) { - HighFive::DataSet buildings_ds = file.getDataSet("buildings/" + faction); + HighFive::DataSet buildingsDs = file.getDataSet("buildings/" + faction); - std::vector<std::vector<std::vector<uint32_t>>> buildings_frames; + std::vector<std::vector<std::vector<uint32_t>>> buildingsFrames; - buildings_ds.read(buildings_frames); + buildingsDs.read(buildingsFrames); - std::vector<uint32_t> building_buffer(32 * 16 * buildings_frames.size(), 0); + std::vector<uint32_t> buildingBuffer(32 * 16 * buildingsFrames.size(), 0); // every type of building - for (size_t n = 0; n < buildings_frames.size(); n++) + for (size_t n = 0; n < buildingsFrames.size(); n++) { for (size_t y = 0; y < 32; y++) { for (size_t x = 0; x < 16; x++) { - size_t index = (y * buildings_frames.size() * 16) + (n * 16 + x); + size_t index = (y * buildingsFrames.size() * 16) + (n * 16 + x); - building_buffer.at(index) = buildings_frames.at(n).at(32 - y - 1).at(x); + buildingBuffer.at(index) = buildingsFrames.at(n).at(32 - y - 1).at(x); } } } SDL_Texture* tmp = SDL_CreateTexture( engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, - buildings_frames.size() * 16, 32); + buildingsFrames.size() * 16, 32); SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND); @@ -151,8 +149,8 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) } if (SDL_UpdateTexture( - tmp, NULL, building_buffer.data(), - buildings_frames.size() * 16 * sizeof(int32_t)) != 0) + tmp, nullptr, buildingBuffer.data(), + buildingsFrames.size() * 16 * sizeof(int32_t)) != 0) { throw std::runtime_error( "Fehler beim updaten der Textur für die Buildings: " + std::string(SDL_GetError())); @@ -161,11 +159,8 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) this->m_buildingTextures.push_back(tmp); } - this->m_buildingWidth = 16; - this->m_buildingHeight = 32; - // Units - std::vector<std::string> unit_factions({"red", "blue", "green", "yellow", "purple"}); + std::vector<std::string> unitFactions({"red", "blue", "green", "yellow", "purple"}); std::vector<std::string> units( {"infantery", "mechanized_infantery", "recon", "medium_tank", "heavy_tank", "neo_tank", @@ -173,53 +168,51 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) "fighter", "bomber", "battle_helicopter", "transport_helicopter", "battleship", "cruiser", "lander", "submarine"}); - std::vector<std::string> unit_states({"idle", "unavailable"}); - std::vector<std::string> unit_movement_states({"left", "right", "down", "up"}); + std::vector<std::string> unitStates({"idle", "unavailable"}); + std::vector<std::string> unitMovementStates({"left", "right", "down", "up"}); // every factions sub data set - for (size_t faction_idx = 0; faction_idx < unit_factions.size(); faction_idx++) + for (size_t factionIdx = 0; factionIdx < unitFactions.size(); factionIdx++) { - std::string faction = unit_factions.at(faction_idx); + const std::string& faction = unitFactions.at(factionIdx); // Create entry for units for in a faction - m_unitTextures.push_back(std::vector<std::vector<std::pair<SDL_Texture*, int>>>()); + m_unitTextures.emplace_back(); // every unit sub data set - for (size_t unit_idx = 0; unit_idx < units.size(); unit_idx++) + for (size_t unitIdx = 0; unitIdx < units.size(); unitIdx++) { - std::string unit = units.at(unit_idx); + const std::string& unit = units.at(unitIdx); // Create entry for states for a unit - m_unitTextures.at(faction_idx).push_back(std::vector<std::pair<SDL_Texture*, int>>()); + m_unitTextures.at(factionIdx).emplace_back(); // every state sub data set - for (size_t state_idx = 0; state_idx < unit_states.size(); state_idx++) + for (const auto& unitState : unitStates) { - std::string unit_state = unit_states.at(state_idx); + HighFive::DataSet unitsDs = + file.getDataSet("units/" + faction + "/" + unit + "/" + unitState); - HighFive::DataSet units_ds = - file.getDataSet("units/" + faction + "/" + unit + "/" + unit_state); + std::vector<std::vector<std::vector<uint32_t>>> unitFrames; + unitsDs.read(unitFrames); - std::vector<std::vector<std::vector<uint32_t>>> unit_frames; - units_ds.read(unit_frames); + std::vector<uint32_t> unitBuffer(16 * 16 * unitFrames.size(), 0); - std::vector<uint32_t> unit_buffer(16 * 16 * unit_frames.size(), 0); - - for (size_t n = 0; n < unit_frames.size(); n++) + for (size_t n = 0; n < unitFrames.size(); n++) { for (size_t y = 0; y < 16; y++) { for (size_t x = 0; x < 16; x++) { - size_t index = (y * unit_frames.size() * 16) + (n * 16 + x); + size_t index = (y * unitFrames.size() * 16) + (n * 16 + x); - unit_buffer.at(index) = unit_frames.at(n).at(16 - y - 1).at(x); + unitBuffer.at(index) = unitFrames.at(n).at(16 - y - 1).at(x); } } } SDL_Texture* tmp = SDL_CreateTexture( engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, - unit_frames.size() * 16, 16); + unitFrames.size() * 16, 16); SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND); @@ -231,49 +224,44 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) } if (SDL_UpdateTexture( - tmp, NULL, unit_buffer.data(), unit_frames.size() * 16 * sizeof(int32_t)) != - 0) + tmp, nullptr, unitBuffer.data(), + unitFrames.size() * 16 * sizeof(int32_t)) != 0) { throw std::runtime_error( "Fehler beim updaten der Textur für die Units: " + std::string(SDL_GetError())); } - m_unitTextures.at(faction_idx) - .at(unit_idx) - .push_back(std::pair<SDL_Texture*, int>(tmp, unit_frames.size())); + m_unitTextures.at(factionIdx).at(unitIdx).emplace_back(tmp, unitFrames.size()); } // every movement state sub data set - for (size_t movement_state_idx = 0; movement_state_idx < unit_movement_states.size(); - movement_state_idx++) + for (const auto& movementState : unitMovementStates) { - std::string movement_state = unit_movement_states.at(movement_state_idx); - - HighFive::DataSet units_ds = file.getDataSet( - "units/" + faction + "/" + unit + "/movement/" + movement_state); + HighFive::DataSet unitsDs = + file.getDataSet("units/" + faction + "/" + unit + "/movement/" + movementState); - std::vector<std::vector<std::vector<uint32_t>>> unit_frames; - units_ds.read(unit_frames); + std::vector<std::vector<std::vector<uint32_t>>> unitFrames; + unitsDs.read(unitFrames); - std::vector<uint32_t> unit_buffer(24 * 24 * unit_frames.size(), 0); + std::vector<uint32_t> unitBuffer(24 * 24 * unitFrames.size(), 0); - for (size_t n = 0; n < unit_frames.size(); n++) + for (size_t n = 0; n < unitFrames.size(); n++) { for (size_t y = 0; y < 24; y++) { for (size_t x = 0; x < 24; x++) { - size_t index = (y * unit_frames.size() * 24) + (n * 24 + x); + size_t index = (y * unitFrames.size() * 24) + (n * 24 + x); - unit_buffer.at(index) = unit_frames.at(n).at(24 - y - 1).at(x); + unitBuffer.at(index) = unitFrames.at(n).at(24 - y - 1).at(x); } } } SDL_Texture* tmp = SDL_CreateTexture( engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, - unit_frames.size() * 24, 24); + unitFrames.size() * 24, 24); SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND); @@ -285,17 +273,15 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) } if (SDL_UpdateTexture( - tmp, NULL, unit_buffer.data(), unit_frames.size() * 24 * sizeof(int32_t)) != - 0) + tmp, nullptr, unitBuffer.data(), + unitFrames.size() * 24 * sizeof(int32_t)) != 0) { throw std::runtime_error( "Fehler beim updaten der Textur für die Units: " + std::string(SDL_GetError())); } - m_unitTextures.at(faction_idx) - .at(unit_idx) - .push_back(std::pair<SDL_Texture*, int>(tmp, unit_frames.size())); + m_unitTextures.at(factionIdx).at(unitIdx).emplace_back(tmp, unitFrames.size()); } } } @@ -311,32 +297,32 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) "submarine_appear"}); // Every effect sub data set - for (size_t effect_idx = 0; effect_idx < effects.size(); effect_idx++) + for (size_t effectIdx = 0; effectIdx < effects.size(); effectIdx++) { - HighFive::DataSet effect_ds = file.getDataSet("effects/" + effects[effect_idx]); + HighFive::DataSet effectDs = file.getDataSet("effects/" + effects[effectIdx]); - std::vector<std::vector<std::vector<uint32_t>>> effect_frames; - effect_ds.read(effect_frames); + std::vector<std::vector<std::vector<uint32_t>>> effectFrames; + effectDs.read(effectFrames); - std::vector<uint32_t> effect_buffer(32 * 32 * effect_frames.size(), 0); + std::vector<uint32_t> effectBuffer(32 * 32 * effectFrames.size(), 0); // every animation frame - for (size_t n = 0; n < effect_frames.size(); n++) + for (size_t n = 0; n < effectFrames.size(); n++) { for (size_t y = 0; y < 32; y++) { for (size_t x = 0; x < 32; x++) { - size_t index = (y * effect_frames.size() * 32) + (n * 32 + x); + size_t index = (y * effectFrames.size() * 32) + (n * 32 + x); - effect_buffer.at(index) = effect_frames.at(n).at(32 - y - 1).at(x); + effectBuffer.at(index) = effectFrames.at(n).at(32 - y - 1).at(x); } } } SDL_Texture* tmp = SDL_CreateTexture( engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, - effect_frames.size() * 32, 32); + effectFrames.size() * 32, 32); SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND); @@ -347,32 +333,32 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) } if (SDL_UpdateTexture( - tmp, NULL, effect_buffer.data(), effect_frames.size() * 32 * sizeof(int32_t)) != 0) + tmp, nullptr, effectBuffer.data(), effectFrames.size() * 32 * sizeof(int32_t)) != 0) { throw std::runtime_error( "Fehler beim updaten der Textur für die Tiles: " + std::string(SDL_GetError())); } - m_effectTextures.push_back(std::pair<SDL_Texture*, int>(tmp, effect_frames.size())); + m_effectTextures.emplace_back(tmp, effectFrames.size()); } this->m_effectWidth = 32; this->m_effectHeight = 32; // Numbers - HighFive::DataSet number_ds = file.getDataSet("/misc/numbers"); + HighFive::DataSet numberDs = file.getDataSet("/misc/numbers"); - std::vector<std::vector<uint32_t>> number_frames; - number_ds.read(number_frames); + std::vector<std::vector<uint32_t>> numberFrames; + numberDs.read(numberFrames); - std::vector<uint32_t> number_buffer(8 * 80, 0); + std::vector<uint32_t> numberBuffer(8 * 80, 0); for (int y = 0; y < 8; y++) { for (int x = 0; x < 80; x++) { - int index = y * 80 + x; - number_buffer.at(index) = number_frames.at(8 - y - 1).at(x); + int index = (y * 80) + x; + numberBuffer.at(index) = numberFrames.at(8 - y - 1).at(x); } } @@ -384,13 +370,13 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) if (tmp == nullptr) { throw std::runtime_error( - "Fehler beim Erstellen der Textur für die Effects: " + std::string(SDL_GetError())); + "Fehler beim Erstellen der Textur für die Numbers: " + std::string(SDL_GetError())); } - if (SDL_UpdateTexture(tmp, NULL, number_buffer.data(), 80 * sizeof(int32_t)) != 0) + if (SDL_UpdateTexture(tmp, nullptr, numberBuffer.data(), 80 * sizeof(int32_t)) != 0) { throw std::runtime_error( - "Fehler beim updaten der Textur für die Tiles: " + std::string(SDL_GetError())); + "Fehler beim updaten der Textur für die Numbers: " + std::string(SDL_GetError())); } this->m_numberTextures = tmp; @@ -413,7 +399,7 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) { size_t index = (y * 8) + x; - number_buffer.at(index) = bulletFrames.at(8 - y - 1).at(x); + numberBuffer.at(index) = bulletFrames.at(8 - y - 1).at(x); } } @@ -425,13 +411,13 @@ Spritesheet::Spritesheet(std::string path, Engine& engine) if (bulletTmp == nullptr) { throw std::runtime_error( - "Fehler beim Erstellen der Textur für die Effects: " + std::string(SDL_GetError())); + "Fehler beim Erstellen der Textur für die Bullets: " + std::string(SDL_GetError())); } - if (SDL_UpdateTexture(bulletTmp, NULL, number_buffer.data(), 8 * sizeof(int32_t)) != 0) + if (SDL_UpdateTexture(bulletTmp, nullptr, numberBuffer.data(), 8 * sizeof(int32_t)) != 0) { throw std::runtime_error( - "Fehler beim updaten der Textur für die Tiles: " + std::string(SDL_GetError())); + "Fehler beim updaten der Textur für die Bullets: " + std::string(SDL_GetError())); } this->m_bulletTexture = bulletTmp; @@ -548,19 +534,19 @@ int Spritesheet::getBulletHeight() Spritesheet::~Spritesheet() { - for (std::pair<SDL_Texture*, int> tile_texture : m_tileTextures) + for (std::pair<SDL_Texture*, int> tileTexture : m_tileTextures) { - SDL_DestroyTexture(tile_texture.first); + SDL_DestroyTexture(tileTexture.first); } - for (SDL_Texture* building_texture : m_buildingTextures) + for (SDL_Texture* buildingTexture : m_buildingTextures) { - SDL_DestroyTexture(building_texture); + SDL_DestroyTexture(buildingTexture); } - for (std::vector<std::vector<std::pair<SDL_Texture*, int>>> faction : m_unitTextures) + for (const std::vector<std::vector<std::pair<SDL_Texture*, int>>>& faction : m_unitTextures) { - for (std::vector<std::pair<SDL_Texture*, int>> unit : faction) + for (const std::vector<std::pair<SDL_Texture*, int>>& unit : faction) { for (std::pair<SDL_Texture*, int> state : unit) { diff --git a/src/game/core/Tile.hpp b/src/game/core/Tile.hpp index de42adf51f041d50e5229dc5818ce17a514499b5..e467b2d213c5efbc843880807f37810a9639d944 100644 --- a/src/game/core/Tile.hpp +++ b/src/game/core/Tile.hpp @@ -11,8 +11,8 @@ class Tile public: Tile(TileId id, int x, int y); - void render(Engine& engine, int scale); - TileId getType() const; + void render(Engine& engine, int scale); + [[nodiscard]] TileId getType() const; private: TileId m_id; diff --git a/src/game/core/Window.cpp b/src/game/core/Window.cpp index 10e16f06a5f2a7f01f4654b621ca908c16d77288..f48c378ff5295b2c653b5aae244fb577e9ace00f 100644 --- a/src/game/core/Window.cpp +++ b/src/game/core/Window.cpp @@ -33,14 +33,14 @@ int Window::h() return m_height; } -SDL_Window* Window::sdl_window() +SDL_Window* Window::sdlWindow() { return m_window; } Window::~Window() { - if (m_window) + if (m_window != nullptr) { SDL_DestroyWindow(m_window); m_window = nullptr; diff --git a/src/game/core/Window.hpp b/src/game/core/Window.hpp index 661ad9412a721665220f9cd7e0d13b6b7386a4e3..55d69ce77c5a5c01308478cf039a8f92538f762a 100644 --- a/src/game/core/Window.hpp +++ b/src/game/core/Window.hpp @@ -38,7 +38,7 @@ class Window /// Returns the current height of the window int h(); - SDL_Window* sdl_window(); + SDL_Window* sdlWindow(); private: /// SDL main window struct diff --git a/src/game/effect/Effect.cpp b/src/game/effect/Effect.cpp index 0d66240d86a91b4bf457749e57ff535e61f30642..7794fa600206a2516fc41c30aa28cccd560fcd66 100644 --- a/src/game/effect/Effect.cpp +++ b/src/game/effect/Effect.cpp @@ -39,12 +39,11 @@ void Effect::render(Engine& engine, int scale) &dest, 0, NULL, SDL_FLIP_NONE); } -bool Effect::is_finished(Engine& engine) +bool Effect::isFinished(Engine& engine) { - return !( - engine.getStage() - m_start <= - engine.getSpritesheet()->getEffectTextures().at(static_cast<int>(m_id)).second || - m_repeat); + return engine.getStage() - m_start > + engine.getSpritesheet()->getEffectTextures().at(static_cast<int>(m_id)).second && + !m_repeat; } } // namespace advanced_wars diff --git a/src/game/effect/Effect.hpp b/src/game/effect/Effect.hpp index e1494f72195224b3d7e8579839bc7434710c0be2..6e0dc91365b573b3726db6ad76f500a0e54ceed1 100644 --- a/src/game/effect/Effect.hpp +++ b/src/game/effect/Effect.hpp @@ -21,7 +21,7 @@ class Effect void render(Engine& engine, int scale); - bool is_finished(Engine& engine); + bool isFinished(Engine& engine); private: int m_x; diff --git a/src/game/entities/Building.cpp b/src/game/entities/Building.cpp index cfe72cb65c8f4f7be1de0188ab13b482ac82de8a..720f69bdf149bb0c8c6b2824c4e6b237e3c260ea 100644 --- a/src/game/entities/Building.cpp +++ b/src/game/entities/Building.cpp @@ -1,7 +1,5 @@ #include "Building.hpp" #include "../core/Spritesheet.hpp" - -#include <algorithm> #include <iostream> namespace advanced_wars @@ -36,25 +34,21 @@ Faction Building::getFaction() return this->m_faction; } -bool Building::switch_faction(Faction faction) +bool Building::switchFaction(Faction faction) { this->m_faction = faction; - if (this->m_id == BuildingId::HEADQUARTER) - { - return true; - } - return false; + return this->m_id == BuildingId::HEADQUARTER; } // implement call to UI to show available units -void Building::on_click() +void Building::onClick() { std::cout << "A building is selected!" << "\n"; }; -bool Building::check_spawn(std::unordered_map<int, std::unique_ptr<Unit>>& units) +bool Building::checkSpawn(std::unordered_map<int, std::unique_ptr<Unit>>& units) { for (auto& [id, unit] : units) { @@ -69,7 +63,7 @@ bool Building::check_spawn(std::unordered_map<int, std::unique_ptr<Unit>>& units return true; } // can be added as soon as the playerobject is available -bool Building::check_money(int price, int playerMoney) +bool Building::checkMoney(int price, int playerMoney) { // replace 400 with player.money and replace price with chosenUnit.price return (playerMoney >= price); diff --git a/src/game/entities/Building.hpp b/src/game/entities/Building.hpp index 68f2cb5249268e2f1a9f3a8f0035ae976649fef2..712014508adf930a09e329a5177044adaae7bbe5 100644 --- a/src/game/entities/Building.hpp +++ b/src/game/entities/Building.hpp @@ -31,23 +31,23 @@ class Building @return true if building was a headquarter */ - bool switch_faction(Faction faction); + bool switchFaction(Faction faction); /* checks if the tile ontop of the building is free */ - bool check_spawn(std::unordered_map<int, std::unique_ptr<Unit>>& units); + bool checkSpawn(std::unordered_map<int, std::unique_ptr<Unit>>& units); /* checks if the player has enough money for the unit to be recruited */ - bool check_money(int price, int playerMoney); + bool checkMoney(int price, int playerMoney); /** If the building is clicked, it shows information to the player, here it will be a list of all available units */ - void on_click(); + void onClick(); /** * Provides a vector of recruitable units, depending on the building id diff --git a/src/game/entities/Bullet.cpp b/src/game/entities/Bullet.cpp index 737ac546c77f830f3a20b6bccad5b0b43dad9b66..719715fc37192f09b3df82b8ddeef48be49b749a 100644 --- a/src/game/entities/Bullet.cpp +++ b/src/game/entities/Bullet.cpp @@ -4,23 +4,22 @@ #include "../physics/PhysicsEngine.hpp" #include "box2d/b2_settings.h" #include <iostream> -#include <stdexcept> namespace advanced_wars { Bullet::Bullet( b2World* world, float startX, float startY, float velocityX, float velocityY, Unit& target) - : m_renderX(0), m_renderY(0), m_target(target) + : m_target(target) { // Erstelle einen PhysicsBody für die Bullet m_physicsBody = std::make_unique<PhysicsBody>( world, startX, startY, 4.0F, 4.0F, 1.0, 0.3, true, BodyType::PROJECTILE); - if (m_physicsBody && m_physicsBody->getBody()) + if (m_physicsBody && (m_physicsBody->getBody() != nullptr)) { BodyUserData* bud = new BodyUserData(); - bud->type = BodyUserData::Type::Bullet; + bud->type = BodyUserData::Type::BULLET; bud->id = target.getUnitId(); bud->data = this; @@ -64,7 +63,7 @@ void Bullet::update() void Bullet::render(Engine& engine, int scale) { // Falls die Textur noch nicht gesetzt wurde, laden wir sie jetzt - if (!m_texture) + if (m_texture == nullptr) { Spritesheet* spritesheet = engine.getSpritesheet(); m_texture = spritesheet->getBulletTexture(); // Textur aus HDF5-File laden diff --git a/src/game/entities/Bullet.hpp b/src/game/entities/Bullet.hpp index 41a8de96cc1d91ccb13ab5b5e757412e2ad9116c..a109214982b6dd7a6c45a22ceff0facd6fe9fb5f 100644 --- a/src/game/entities/Bullet.hpp +++ b/src/game/entities/Bullet.hpp @@ -34,13 +34,13 @@ class Bullet void render(Engine& engine, int scale); /// Gibt den Box2D-Body zurück (nützlich z.B. für Kollisionsbehandlung) - PhysicsBody& getBody() const; + [[nodiscard]] PhysicsBody& getBody() const; void destroy(); void setDestroyFlag(bool flag); - bool shouldDestroy() const { return m_destroyFlag; } + [[nodiscard]] bool shouldDestroy() const { return m_destroyFlag; } Unit& getTarget() { return m_target; } diff --git a/src/game/entities/Unit.cpp b/src/game/entities/Unit.cpp index 3977ae8a926b234f02b776678d9c34f62b0276fc..f7c82fb777c7afa2adb90e1b9edf9b2e9488e8d8 100644 --- a/src/game/entities/Unit.cpp +++ b/src/game/entities/Unit.cpp @@ -2,9 +2,6 @@ #include "../core/Config.hpp" #include "../physics/PhysicsBody.hpp" #include "../physics/PhysicsEngine.hpp" -#include "box2d/box2d.h" - -#include <iostream> #include <memory> namespace advanced_wars @@ -24,10 +21,10 @@ Unit::Unit( m_physicsBody = std::make_unique<PhysicsBody>( m_world, tileX, tileY, 8.0F, 8.0F, 1.0, 0.3, true, BodyType::UNIT); - if (m_physicsBody && m_physicsBody->getBody()) + if (m_physicsBody && (m_physicsBody->getBody() != nullptr)) { BodyUserData* bud = new BodyUserData(); - bud->type = BodyUserData::Type::Unit; + bud->type = BodyUserData::Type::UNIT; bud->id = m_unitId; bud->data = this; @@ -121,7 +118,8 @@ void Unit::render(Engine& engine, int scale) .at(static_cast<int>(m_state)) .second; - SDL_Rect src, dst; + SDL_Rect src; + SDL_Rect dst; if (m_state == UnitState::IDLE || m_state == UnitState::UNAVAILABLE) { src.x = step * spritesheet->getUnitWidth(); @@ -168,7 +166,8 @@ void Unit::renderHP(Engine& engine, int scale) int unitHp = ceil((double)m_health / 10); - SDL_Rect src, dest; + SDL_Rect src; + SDL_Rect dest; src.x = unitHp % 10 * numberWidth; src.y = 0; src.w = numberWidth; diff --git a/src/game/entities/Unit.hpp b/src/game/entities/Unit.hpp index 73e74bb66716a449093b154872593d3eb98a523b..0e05e8e4a775aa6de82c00a52c561260e3978282 100644 --- a/src/game/entities/Unit.hpp +++ b/src/game/entities/Unit.hpp @@ -7,8 +7,6 @@ #include <SDL_events.h> #include <memory> -#include <unordered_map> -#include <vector> namespace advanced_wars { @@ -48,26 +46,26 @@ class Unit void renderHP(Engine& engine, int scale); // Getter-Methoden - int getXPosition() const { return m_tileX; }; - int getYPosition() const { return m_tileY; }; - Faction getFaction() { return this->m_faction; } - - void setState(UnitState state) { this->m_state = state; } - int getAmmo() const { return m_ammo; } - int getHealth() const { return m_health; } - int getCost() const { return m_cost; } - UnitTypeId getUnitTypeId() const { return m_unitTypeId; } - int getMovementPoints() const { return m_movementPoints; } - MovementType getMovementType() const { return m_movementType; } - UnitState getState() const { return m_state; } - bool hasMoved() const { return this->m_hasMoved; } - void setMoved(bool moved) { m_hasMoved = moved; } - bool hasAttacked() const { return this->m_hasAttacked; } - int getMaxHealth() const { return m_maxHealth; } - int getMinRange() const { return m_minRange; } - int getMaxRange() const { return m_maxRange; } - Weapon& getPrimaryWeapon() { return *m_primaryWeapon; } - Weapon& getSecondaryWeapon() { return *m_secondaryWeapon; } + [[nodiscard]] int getXPosition() const { return m_tileX; }; + [[nodiscard]] int getYPosition() const { return m_tileY; }; + Faction getFaction() { return this->m_faction; } + + void setState(UnitState state) { this->m_state = state; } + [[nodiscard]] int getAmmo() const { return m_ammo; } + [[nodiscard]] int getHealth() const { return m_health; } + [[nodiscard]] int getCost() const { return m_cost; } + [[nodiscard]] UnitTypeId getUnitTypeId() const { return m_unitTypeId; } + [[nodiscard]] int getMovementPoints() const { return m_movementPoints; } + [[nodiscard]] MovementType getMovementType() const { return m_movementType; } + [[nodiscard]] UnitState getState() const { return m_state; } + [[nodiscard]] bool hasMoved() const { return this->m_hasMoved; } + void setMoved(bool moved) { m_hasMoved = moved; } + [[nodiscard]] bool hasAttacked() const { return this->m_hasAttacked; } + [[nodiscard]] int getMaxHealth() const { return m_maxHealth; } + [[nodiscard]] int getMinRange() const { return m_minRange; } + [[nodiscard]] int getMaxRange() const { return m_maxRange; } + Weapon& getPrimaryWeapon() { return *m_primaryWeapon; } + Weapon& getSecondaryWeapon() { return *m_secondaryWeapon; } int getUnitId() { return m_unitId; } diff --git a/src/game/level/Level.cpp b/src/game/level/Level.cpp index d38ba277b81d284fbe5e050915b37c26112f372c..394a49e155ed6b69c2211b957f7ddd985b489b7a 100644 --- a/src/game/level/Level.cpp +++ b/src/game/level/Level.cpp @@ -10,8 +10,6 @@ #include "../ui/menu/EndScreen.hpp" #include "../ui/menu/PauseMenu.hpp" #include "../ui/modals/HelpMenu.hpp" -#include "SDL_timer.h" -#include "box2d/box2d.h" #include <SDL.h> #include <boost/property_tree/ptree.hpp> @@ -27,8 +25,7 @@ namespace advanced_wars const int RENDERING_SCALE = 3; Level::Level(const std::string& path, Engine& engine) - : m_selectedUnit(-1), m_selectedBuilding(-1), m_contextMenu(ContextMenu()), m_id(0), - m_state(LevelState::SELECTING_STATE) + : m_selectedUnit(-1), m_selectedBuilding(-1), m_id(0), m_state(LevelState::SELECTING_STATE) { m_contextMenu.setOptions({"Move", "Info", "Wait"}); @@ -38,44 +35,43 @@ Level::Level(const std::string& path, Engine& engine) HighFive::File file(path, HighFive::File::ReadOnly); // read level metadata - std::string level_metadata; - file.getDataSet("metadata").read(level_metadata); + std::string levelMetadata; + file.getDataSet("metadata").read(levelMetadata); // read tilesarray - std::vector<uint8_t> level_tilesarray; - file.getDataSet("tilesarray").read(level_tilesarray); - std::cout << "tilesarray size: " << level_tilesarray.size() << "\n"; + std::vector<uint8_t> levelTilesarray; + file.getDataSet("tilesarray").read(levelTilesarray); + std::cout << "tilesarray size: " << levelTilesarray.size() << "\n"; // extract metadata from xml - std::istringstream xmlStream(level_metadata); + std::istringstream xmlStream(levelMetadata); boost::property_tree::ptree pt; boost::property_tree::read_xml(xmlStream, pt); m_width = pt.get<int>("level.width"); m_height = pt.get<int>("level.height"); - std::string name = pt.get<std::string>("level.name"); // if level is smaler than 20x20 surround with water tiles if (m_width < 20 || m_height < 20) { - int x_start = (20 - m_width) / 2; - int y_start = (20 - m_height) / 2; - std::vector<uint8_t> transformed_tiles_array; - transformed_tiles_array.reserve(20 * 20); + int xStart = (20 - m_width) / 2; + int yStart = (20 - m_height) / 2; + std::vector<uint8_t> transformedTilesArray; + transformedTilesArray.reserve(20 * 20); for (int y = 0; y < 20; y++) { for (int x = 0; x < 20; x++) { - if (x < x_start || y < y_start || x >= x_start + m_width || y >= y_start + m_height) + if (x < xStart || y < yStart || x >= xStart + m_width || y >= yStart + m_height) { - transformed_tiles_array.push_back(1); + transformedTilesArray.push_back(1); } else { - transformed_tiles_array.push_back( - level_tilesarray[x - x_start + (y - y_start) * m_width]); + transformedTilesArray.push_back( + levelTilesarray[x - xStart + ((y - yStart) * m_width)]); } } } - level_tilesarray = std::move(transformed_tiles_array); + levelTilesarray = std::move(transformedTilesArray); m_width = 20; m_height = 20; } @@ -86,38 +82,38 @@ Level::Level(const std::string& path, Engine& engine) std::vector<Tile> tiles; std::vector<Building> buildings; tiles.reserve(m_width * m_height); - bool has_factions[] = {false, false, false, false, false}; - for (size_t i = 0; i < level_tilesarray.size(); i++) + bool hasFactions[] = {false, false, false, false, false}; + for (size_t i = 0; i < levelTilesarray.size(); i++) { int tileX = i % m_width; int tileY = i / m_width; - if (level_tilesarray[i] >= 50) + if (levelTilesarray[i] >= 50) { // tile id >= 50 -> building -> have to add Plain Tile and Building tiles.push_back(Tile(TileId(TileId::PLAIN), tileX, tileY)); - BuildingId building_id = static_cast<BuildingId>((level_tilesarray[i] - 50) % 5); - Faction faction_id = static_cast<Faction>((level_tilesarray[i] - 50) / 5); - if (building_id == BuildingId::HEADQUARTER) + auto buildingId = static_cast<BuildingId>((levelTilesarray[i] - 50) % 5); + auto factionId = static_cast<Faction>((levelTilesarray[i] - 50) / 5); + if (buildingId == BuildingId::HEADQUARTER) { // an infantery unit should be added onto every HQ - int index = static_cast<int>(faction_id); - if (!has_factions[index]) + int index = static_cast<int>(factionId); + if (!hasFactions[index]) { addUnit( - tileX, tileY, faction_id, UnitTypeId::INFANTERY, UnitState::UNAVAILABLE, + tileX, tileY, factionId, UnitTypeId::INFANTERY, UnitState::UNAVAILABLE, engine.getUnitConfig()); } - has_factions[static_cast<int>(faction_id)] = true; // collect existing factions - // for later building turnQ + hasFactions[static_cast<int>(factionId)] = true; // collect existing factions + // for later building turnQ } - buildings.push_back(Building(tileX, tileY, building_id, faction_id)); + buildings.push_back(Building(tileX, tileY, buildingId, factionId)); } else { // if tile id belongs to terrain tile, just a tile needs to added - TileId tile_id = static_cast<TileId>(level_tilesarray[i]); - tiles.push_back(Tile(tile_id, tileX, tileY)); + auto tileId = static_cast<TileId>(levelTilesarray[i]); + tiles.emplace_back(tileId, tileX, tileY); } } @@ -137,7 +133,7 @@ Level::Level(const std::string& path, Engine& engine) std::queue<Player> turnQ; for (int i = 0; i < 5; i++) { - if (has_factions[i]) + if (hasFactions[i]) { std::cout << "Faction: " << i << "\n"; turnQ.push(Player(2000, static_cast<Faction>(i))); @@ -162,7 +158,9 @@ void Level::selectEntity(int x, int y) { std::pair<int, int> tilePos = calcTilePos(x, y); - if ((m_selectedUnit = selectUnit(tilePos.first, tilePos.second)) >= 0) + auto tmp = (m_selectedUnit = selectUnit(tilePos.first, tilePos.second)); + + if (tmp >= 0) { auto it = m_units.find(m_selectedUnit); if (it != m_units.end()) @@ -221,7 +219,7 @@ void Level::handleEvent(Engine& engine, SDL_Event& event) { if (event.key.keysym.sym == SDLK_h) { - toggle_Helpmenu = !toggle_Helpmenu; + m_toggleHelpmenu = !m_toggleHelpmenu; } } switch (m_state) @@ -266,7 +264,9 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit) // Check if this tile has been visited already if (visited[x][y]) + { continue; + } visited[x][y] = true; // Check if a unit is on the current tile, skip adding it if true @@ -286,22 +286,24 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit) reachableTiles.emplace_back(x, y); } - static const std::vector<std::pair<int, int>> directions = { + static const std::vector<std::pair<int, int>> DIRECTIONS = { { 1, 0}, {-1, 0}, { 0, 1}, { 0, -1} }; - for (const auto& [dx, dy] : directions) + for (const auto& [dx, dy] : DIRECTIONS) { int nx = x + dx; int ny = y + dy; if (nx < 0 || nx >= m_width || ny < 0 || ny >= m_height) + { continue; // Boundary check + } - int cost = getMoveCost(m_tiles[ny * m_width + nx].getType(), unit.getMovementType()); + int cost = getMoveCost(m_tiles[(ny * m_width) + nx].getType(), unit.getMovementType()); if (cost >= 0 && remainingMovement >= cost) { wavefrontQueue.push(std::make_tuple(nx, ny, remainingMovement - cost)); @@ -314,7 +316,7 @@ std::vector<std::pair<int, int>> Level::calculateMovementRange(Unit& unit) int Level::getMoveCost(TileId tileId, MovementType movementType) { - return moveCostTable[static_cast<int>(tileId)][static_cast<int>(movementType)]; + return MOVE_COST_TABLE[static_cast<int>(tileId)][static_cast<int>(movementType)]; } void Level::render(Engine& engine) @@ -373,12 +375,12 @@ void Level::render(Engine& engine) } // Effects - std::vector<int> effects_to_remove; + std::vector<int> effectsToRemove; for (auto& [id, effect] : m_effects) { - if (effect.is_finished(engine)) + if (effect.isFinished(engine)) { - effects_to_remove.push_back(id); + effectsToRemove.push_back(id); } else { @@ -401,7 +403,7 @@ void Level::render(Engine& engine) } // Remove finished effects after iteration - for (int id : effects_to_remove) + for (int id : effectsToRemove) { this->removeEffect(id); } @@ -423,7 +425,7 @@ void Level::render(Engine& engine) m_currentPos.render(engine); - if (toggle_Helpmenu) + if (m_toggleHelpmenu) { m_helpMenu.render(engine); } @@ -495,7 +497,7 @@ void Level::spawnBullet(Unit& attacker, Unit& target) float deltaX = targetX - startX; float deltaY = targetY - startY; - float distance = std::sqrt(deltaX * deltaX + deltaY * deltaY); + float distance = std::sqrt((deltaX * deltaX) + (deltaY * deltaY)); if (distance == 0.0F) { @@ -546,16 +548,16 @@ void Level::handleRecruitingEvent(Engine& engine, SDL_Event& event) if (event.key.keysym.sym == SDLK_RETURN) { Building& b = m_buildings.at(m_selectedBuilding); - Faction factionId = static_cast<Faction>(b.getFaction()); - UnitTypeId unit_id = m_recruitingMenu.getSelectedOption(); - int cost = engine.getUnitConfig().getUnitCost(unit_id); + Faction factionId = b.getFaction(); + UnitTypeId unitId = m_recruitingMenu.getSelectedOption(); + int cost = engine.getUnitConfig().getUnitCost(unitId); - if (b.check_money(cost, m_turnQ.front().getMoney())) + if (b.checkMoney(cost, m_turnQ.front().getMoney())) { - if (b.check_spawn(m_units)) + if (b.checkSpawn(m_units)) { addUnit( - b.getXPosition(), b.getYPosition(), factionId, unit_id, UnitState::IDLE, + b.getXPosition(), b.getYPosition(), factionId, unitId, UnitState::IDLE, engine.getUnitConfig()); m_state = LevelState::SELECTING_STATE; m_turnQ.front().spendMoney(cost); @@ -607,6 +609,7 @@ void Level::handleMovement(std::pair<int, int> tilePos) std::vector<Unit*> allUnits; + allUnits.reserve(m_units.size()); for (auto& [id, unit] : m_units) { allUnits.push_back(unit.get()); @@ -699,6 +702,7 @@ void Level::handleSelectingEvents(Engine& engine, SDL_Event& event) } m_reachableTiles = calculateMovementRange(*m_units.at(m_selectedUnit)); std::vector<Unit*> allUnits; + allUnits.reserve(m_units.size()); for (auto& [id, unit] : m_units) { allUnits.push_back(unit.get()); @@ -713,7 +717,7 @@ void Level::handleSelectingEvents(Engine& engine, SDL_Event& event) m_attackableUnitIds.clear(); // Set Fallback_position if movement will be canceled - unit_fallback_position = std::make_pair( + m_unitFallbackPosition = std::make_pair( m_units.at(m_selectedUnit)->getXPosition(), m_units.at(m_selectedUnit)->getYPosition()); @@ -744,7 +748,7 @@ void Level::handleSelectingEvents(Engine& engine, SDL_Event& event) if (building.getXPosition() == u.getXPosition() && building.getYPosition() == u.getYPosition()) { - if (static_cast<Faction>(building.getFaction()) != u.getFaction()) + if (building.getFaction() != u.getFaction()) { m_captureBuilding = id; m_contextMenu.setOptions( @@ -768,12 +772,11 @@ void Level::handleSelectingEvents(Engine& engine, SDL_Event& event) } else { - BuildingId b_id = m_buildings.at(m_selectedBuilding).getId(); - Faction b_faction = - static_cast<Faction>(m_buildings.at(m_selectedBuilding).getFaction()); + BuildingId bId = m_buildings.at(m_selectedBuilding).getId(); + auto bFaction = m_buildings.at(m_selectedBuilding).getFaction(); - if (b_id == BuildingId::CITY || b_id == BuildingId::HEADQUARTER || - b_faction == static_cast<Faction>(5)) + if (bId == BuildingId::CITY || bId == BuildingId::HEADQUARTER || + bFaction == static_cast<Faction>(5)) { m_contextMenu.setOptions({"Info", "End Turn"}); } @@ -781,7 +784,7 @@ void Level::handleSelectingEvents(Engine& engine, SDL_Event& event) { // Show according menu options if building has same/different faction than // current player - if (b_faction == m_turnQ.front().getFaction()) + if (bFaction == m_turnQ.front().getFaction()) { m_contextMenu.setOptions({"Train", "Info", "End Turn"}); } @@ -808,12 +811,12 @@ void Level::handleMenuActiveEvents(Engine& engine, SDL_Event& event) if (event.key.keysym.sym == SDLK_ESCAPE) { if (m_selectedUnit > -1 && - unit_fallback_position != std::make_pair( + m_unitFallbackPosition != std::make_pair( m_units.at(m_selectedUnit)->getXPosition(), m_units.at(m_selectedUnit)->getYPosition())) { m_units.at(m_selectedUnit) - ->moveTo(unit_fallback_position.first, unit_fallback_position.second); + ->moveTo(m_unitFallbackPosition.first, m_unitFallbackPosition.second); } m_selectedUnit = -1; m_selectedBuilding = -1; @@ -894,10 +897,10 @@ void Level::handleMenuActiveEvents(Engine& engine, SDL_Event& event) if (cmd == "Capture") { Building& b = m_buildings.at(m_captureBuilding); - Faction u_f = m_units.at(m_selectedUnit)->getFaction(); + Faction uF = m_units.at(m_selectedUnit)->getFaction(); - auto b_f = static_cast<Faction>(u_f); - m_gameOver = b.switch_faction(b_f); + auto bF = uF; + m_gameOver = b.switchFaction(bF); m_units.at(m_selectedUnit)->setState(UnitState::UNAVAILABLE); m_state = LevelState::SELECTING_STATE; diff --git a/src/game/level/Level.hpp b/src/game/level/Level.hpp index ddca6329d4cf5a952b3fec0f1ccf0ce77d0933f6..f606e4cf9f4ed396e4f0322d52012607a7e25fc1 100644 --- a/src/game/level/Level.hpp +++ b/src/game/level/Level.hpp @@ -31,7 +31,7 @@ namespace advanced_wars const int NUM_TILE_IDS = 30; // Aktualisieren, falls weitere IDs hinzugefügt werden const int NUM_MOVEMENT_TYPES = 6; -const std::array<std::array<int, NUM_MOVEMENT_TYPES>, NUM_TILE_IDS> moveCostTable = { +const std::array<std::array<int, NUM_MOVEMENT_TYPES>, NUM_TILE_IDS> MOVE_COST_TABLE = { { // FOOT, WHEELED, TREAD, AIR, SEA, LANDER {1, 2, 1, 1, 999, 999}, // PLAIN @@ -90,7 +90,7 @@ class Level : public Scene // std::vector<Building> buildings, std::vector<Effect> effects, std::queue<Player> // turnQ); - void render(Engine& engine); + void render(Engine& engine) override; /* on event @@ -107,7 +107,7 @@ class Level : public Scene button left -> select field/building/unit/ move to position */ - void handleEvent(Engine& engine, SDL_Event& event); + void handleEvent(Engine& engine, SDL_Event& event) override; int addBuilding(Building building); @@ -127,10 +127,6 @@ class Level : public Scene int getMoveCost(TileId type, MovementType movementType); - std::vector<std::pair<int, int>> m_reachableTiles; - - std::vector<std::pair<int, int>> m_attackableTiles; - std::pair<int, int> calcTilePos(int mouseX, int mouseY); void selectEntity(int x, int y); int selectUnit(int tileX, int tileY); @@ -175,17 +171,18 @@ class Level : public Scene std::unordered_map<int, Building> m_buildings; std::unordered_map<int, std::unique_ptr<Unit>> m_units; int m_unitIdIterator = 5; - // std::unordered_map<int, Unit> m_units; - std::unordered_map<int, Effect> m_effects; - std::unique_ptr<Bullet> m_bullet; - std::queue<Player> m_turnQ; + std::vector<std::pair<int, int>> m_reachableTiles; + std::vector<std::pair<int, int>> m_attackableTiles; + std::unordered_map<int, Effect> m_effects; + std::unique_ptr<Bullet> m_bullet; + std::queue<Player> m_turnQ; int m_selectedUnit; int m_selectedBuilding; int m_captureBuilding; ContextMenu m_contextMenu; RecruitingMenu m_recruitingMenu; - bool toggle_Helpmenu = false; + bool m_toggleHelpmenu = false; HelpMenu m_helpMenu; int m_id; LevelState m_state; @@ -195,7 +192,7 @@ class Level : public Scene std::unordered_set<int> m_attackableUnitIds; UnitInfoMenu m_unitInfoMenu; bool m_showUnitInfoMenu = false; - std::pair<int, int> unit_fallback_position; + std::pair<int, int> m_unitFallbackPosition; std::unique_ptr<PhysicsEngine> m_physicsEngine; std::unique_ptr<CombatEngine> m_combatEngine; Uint32 m_lastFrameTime = 0; diff --git a/src/game/main.cpp b/src/game/main.cpp index 32481dc6411566e20e1c0dde4ac24ccbd0096c6c..395ecf0e04592383558a4017e7e64af50b82dab3 100644 --- a/src/game/main.cpp +++ b/src/game/main.cpp @@ -4,21 +4,21 @@ #include "ui/context/ContextMenu.hpp" #include "ui/menu/Menu.hpp" +#include <QCommandLineParser> +#include <QCoreApplication> #include <SDL2/SDL.h> #include <SDL_image.h> -#include <QCoreApplication> -#include <QCommandLineParser> +#include <filesystem> #include <iostream> #include <memory> +#include <optional> #include <stdexcept> -#include <vector> #include <string> -#include <optional> -#include <filesystem> +#include <vector> using namespace advanced_wars; -std::optional<std::string> get_level_filepath(int argc, char* argv[]) +std::optional<std::string> getLevelFilepath(int argc, char* argv[]) { QCoreApplication app(argc, argv); QCoreApplication::setApplicationVersion("1.0.0"); @@ -26,19 +26,21 @@ std::optional<std::string> get_level_filepath(int argc, char* argv[]) parser.addVersionOption(); parser.addHelpOption(); - parser.setApplicationDescription("Advanced Wars is a multi player strategy game.\nCapture citys, build units and defeat your opponents. No mercy!"); - parser.addPositionalArgument("path", "The path to the HDF5 level file from which the level should be loaded.", "<path>"); + parser.setApplicationDescription("Advanced Wars is a multi player strategy game.\nCapture " + "citys, build units and defeat your opponents. No mercy!"); + parser.addPositionalArgument( + "path", "The path to the HDF5 level file from which the level should be loaded.", "<path>"); parser.process(app); if (parser.positionalArguments().size() != 1) { - std::cerr << "Command not recognized." << std::endl; + std::cerr << "Command not recognized." << '\n'; parser.showHelp(); return std::nullopt; } std::string filepath = parser.positionalArguments()[0].toStdString(); if (!std::filesystem::exists(filepath)) { - std::cerr << "The hdf5 level file path: '" << filepath <<"' does not exist." << std::endl; + std::cerr << "The hdf5 level file path: '" << filepath << "' does not exist." << '\n'; return std::nullopt; } return parser.positionalArguments()[0].toStdString(); @@ -46,8 +48,8 @@ std::optional<std::string> get_level_filepath(int argc, char* argv[]) int main(int argc, char* argv[]) { - std::optional<std::string> level_filepath = get_level_filepath(argc, argv); - if (!level_filepath.has_value()) + std::optional<std::string> levelFilepath = getLevelFilepath(argc, argv); + if (!levelFilepath.has_value()) { return 1; } @@ -58,7 +60,7 @@ int main(int argc, char* argv[]) } int imgFlags = IMG_INIT_PNG; - if (!(IMG_Init(imgFlags) & imgFlags)) + if ((IMG_Init(imgFlags) & imgFlags) == 0) { throw std::runtime_error( "SDL_image could not initialize! SDL_image Error: " + std::string(IMG_GetError())); @@ -72,14 +74,14 @@ int main(int argc, char* argv[]) engine.setSpritesheet(spritesheet); - std::shared_ptr<Menu> menu = std::make_shared<Menu>(0, level_filepath.value()); - std::shared_ptr<ContextMenu> context_menu = std::make_shared<ContextMenu>(); - context_menu->setOptions({"Move", "Info", "Wait"}); + std::shared_ptr<Menu> menu = std::make_shared<Menu>(0, levelFilepath.value()); + std::shared_ptr<ContextMenu> contextMenu = std::make_shared<ContextMenu>(); + contextMenu->setOptions({"Move", "Info", "Wait"}); std::string basePath = SDL_GetBasePath(); std::string relativePath = "res/main_background.png"; std::string fullPath = basePath + relativePath; - menu->loadBackground(engine, fullPath.c_str()); + menu->loadBackground(engine, fullPath); engine.pushScene(menu); diff --git a/src/game/physics/PhysicsBody.cpp b/src/game/physics/PhysicsBody.cpp index c7b31c34276ee9f3395afd3e129f40656283ba7b..24bbaf9afe750aa0828970511aaa81695cebc135 100644 --- a/src/game/physics/PhysicsBody.cpp +++ b/src/game/physics/PhysicsBody.cpp @@ -29,9 +29,9 @@ PhysicsBody::PhysicsBody( m_fixture = m_body->CreateFixture(&fixtureDef); } -void PhysicsBody::update(float deltaTime) +void PhysicsBody::update(float /*deltaTime*/) { - if (!m_body) + if (m_body == nullptr) { return; } @@ -43,7 +43,7 @@ void PhysicsBody::update(float deltaTime) b2Vec2 currentPos = getPosition(); float deltaX = worldTargetX - currentPos.x; float deltaY = worldTargetY - currentPos.y; - float distance = std::sqrt(deltaX * deltaX + deltaY * deltaY); + float distance = std::sqrt((deltaX * deltaX) + (deltaY * deltaY)); if (distance < 0.01F) // Exakte Prüfung auf Tile-Zentrum { @@ -72,7 +72,7 @@ void PhysicsBody::setTargetPosition(int targetTileX, int targetTileY) b2Vec2 PhysicsBody::getPosition() const { - if (m_body) + if (m_body != nullptr) { return m_body->GetPosition(); } @@ -81,7 +81,7 @@ b2Vec2 PhysicsBody::getPosition() const b2Vec2 PhysicsBody::getVelocity() const { - if (m_body) + if (m_body != nullptr) { return m_body->GetLinearVelocity(); } @@ -90,7 +90,7 @@ b2Vec2 PhysicsBody::getVelocity() const void PhysicsBody::destroy() { - if (m_body && m_world) + if ((m_body != nullptr) && (m_world != nullptr)) { m_world->DestroyBody(m_body); m_body = nullptr; @@ -99,7 +99,7 @@ void PhysicsBody::destroy() void PhysicsBody::setVelocity(b2Vec2 velocity) { - if (m_body) + if (m_body != nullptr) { m_body->SetLinearVelocity(velocity); } diff --git a/src/game/physics/PhysicsEngine.cpp b/src/game/physics/PhysicsEngine.cpp index da8bdb2bed20fb3711af73dcb8df35c9a24bfc19..54884b33a68273ebe676ae6f2e6531a9ec6261e5 100644 --- a/src/game/physics/PhysicsEngine.cpp +++ b/src/game/physics/PhysicsEngine.cpp @@ -31,10 +31,10 @@ void PhysicsEngine::BeginContact(b2Contact* contact) void* bodyUserDataA = reinterpret_cast<void*>(fixtureA->GetBody()->GetUserData().pointer); void* bodyUserDataB = reinterpret_cast<void*>(fixtureB->GetBody()->GetUserData().pointer); - BodyUserData* budA = reinterpret_cast<BodyUserData*>(bodyUserDataA); - BodyUserData* budB = reinterpret_cast<BodyUserData*>(bodyUserDataB); + auto* budA = reinterpret_cast<BodyUserData*>(bodyUserDataA); + auto* budB = reinterpret_cast<BodyUserData*>(bodyUserDataB); - if (!budA || !budB) + if ((budA == nullptr) || (budB == nullptr)) { return; } @@ -43,25 +43,25 @@ void PhysicsEngine::BeginContact(b2Contact* contact) Bullet* bullet = nullptr; Unit* unit = nullptr; - if (budA->type == BodyUserData::Type::Bullet) + if (budA->type == BodyUserData::Type::BULLET) { bullet = static_cast<Bullet*>(budA->data); } - else if (budA->type == BodyUserData::Type::Unit) + else if (budA->type == BodyUserData::Type::UNIT) { unit = static_cast<Unit*>(budA->data); } - if (budB->type == BodyUserData::Type::Bullet) + if (budB->type == BodyUserData::Type::BULLET) { bullet = static_cast<Bullet*>(budB->data); } - else if (budB->type == BodyUserData::Type::Unit) + else if (budB->type == BodyUserData::Type::UNIT) { unit = static_cast<Unit*>(budB->data); } - if (!bullet || !unit) + if ((bullet == nullptr) || (unit == nullptr)) { return; } @@ -74,7 +74,7 @@ void PhysicsEngine::BeginContact(b2Contact* contact) } // **Bullet soll zerstört werden** - if (bullet) + if (bullet != nullptr) { bullet->setDestroyFlag(true); } diff --git a/src/game/physics/PhysicsEngine.hpp b/src/game/physics/PhysicsEngine.hpp index 1183f738021761ea04d468b32a7af707dfe2cfc1..a59683eb30202a209b0cf7cd7ed8916227a0ce0e 100644 --- a/src/game/physics/PhysicsEngine.hpp +++ b/src/game/physics/PhysicsEngine.hpp @@ -3,8 +3,6 @@ #include "PhysicsBody.hpp" #include "box2d/box2d.h" -#include <vector> - namespace advanced_wars { @@ -12,8 +10,8 @@ struct BodyUserData { enum class Type { - Unit = 0, - Bullet = 1, + UNIT = 0, + BULLET = 1, }; Type type; int id; diff --git a/src/game/ui/TileMarker.cpp b/src/game/ui/TileMarker.cpp index e6e6122a75c4b25ec137a85dc34a8f5c3741cb1a..856915c370b273d6d994c9c48084b880ba3b8e41 100644 --- a/src/game/ui/TileMarker.cpp +++ b/src/game/ui/TileMarker.cpp @@ -28,12 +28,12 @@ void TileMarker::setBounds(int width, int height) m_levelHeight = height; } -void TileMarker::handleEvent(Engine& engine, SDL_Event& event) +void TileMarker::handleEvent(Engine& /*engine*/, SDL_Event& event) { if (event.type == SDL_KEYDOWN) { - int newX; - int newY; + int newX = 0; + int newY = 0; switch (event.key.keysym.sym) { case SDLK_UP: diff --git a/src/game/ui/context/ContextMenu.cpp b/src/game/ui/context/ContextMenu.cpp index 7d350d0e27528cf165eb8a5009b7422b564a8b72..99cf79ff9bc581d98e32309b15be0b9130964d6b 100644 --- a/src/game/ui/context/ContextMenu.cpp +++ b/src/game/ui/context/ContextMenu.cpp @@ -35,7 +35,7 @@ void ContextMenu::render(Engine& engine) std::string relativePath = "res/ARCADECLASSIC.TTF"; std::string fullPath = basePath + relativePath; TTF_Font* font = TTF_OpenFont(fullPath.c_str(), 16); - if (!font) + if (font == nullptr) { std::cerr << "Failed to load font: " << TTF_GetError() << "\n"; return; @@ -56,7 +56,7 @@ void ContextMenu::render(Engine& engine) { SDL_Surface* textSurface = TTF_RenderText_Solid( font, m_options[i].c_str(), (i == m_selectedOption) ? yellow : white); - if (!textSurface) + if (textSurface == nullptr) { continue; } @@ -74,7 +74,7 @@ void ContextMenu::render(Engine& engine) TTF_Quit(); } -void ContextMenu::handleEvent(Engine& engine, SDL_Event& event) +void ContextMenu::handleEvent(Engine& /*engine*/, SDL_Event& event) { if (event.type == SDL_KEYDOWN) { diff --git a/src/game/ui/context/ContextMenu.hpp b/src/game/ui/context/ContextMenu.hpp index 9f4e8d8ce96e6bc5941676345fa426ce198bb0ad..165433ec173225f0cecd767a4c61ec1eb6f4cee5 100644 --- a/src/game/ui/context/ContextMenu.hpp +++ b/src/game/ui/context/ContextMenu.hpp @@ -19,7 +19,7 @@ class ContextMenu : public Scene void render(Engine& engine) override; - void handleEvent(Engine& engine, SDL_Event& event); + void handleEvent(Engine& engine, SDL_Event& event) override; void update(int x, int y); diff --git a/src/game/ui/context/RecruitingMenu.cpp b/src/game/ui/context/RecruitingMenu.cpp index 6172c4f5f8ededa2659b244ab70f4e201534b7ba..004de44eb86d8a20481c55e92a370e12d54d84be 100644 --- a/src/game/ui/context/RecruitingMenu.cpp +++ b/src/game/ui/context/RecruitingMenu.cpp @@ -6,7 +6,7 @@ namespace advanced_wars { RecruitingMenu::RecruitingMenu() - : m_selectedOption(0), unitNames({ + : m_selectedOption(0), m_unitNames({ { UnitTypeId::INFANTERY, "Infantry"}, { UnitTypeId::MECHANIZED_INFANTERY, "Bazooka"}, { UnitTypeId::RECON, "Recon"}, @@ -58,7 +58,7 @@ void RecruitingMenu::render(Engine& engine) std::string relativePath = "res/ARCADECLASSIC.TTF"; std::string fullPath = basePath + relativePath; TTF_Font* font = TTF_OpenFont(fullPath.c_str(), 16); - if (!font) + if (font == nullptr) { std::cerr << "Failed to load font: " << TTF_GetError() << "\n"; return; @@ -85,42 +85,40 @@ void RecruitingMenu::render(Engine& engine) } SDL_Surface* textSurface = TTF_RenderText_Solid( - font, unitNames.at(id).c_str(), (i == m_selectedOption) ? yellow : white); - if (!textSurface) + font, m_unitNames.at(id).c_str(), (i == m_selectedOption) ? yellow : white); + if (textSurface == nullptr) { continue; } SDL_Texture* textTexture = SDL_CreateTextureFromSurface(engine.renderer(), textSurface); - SDL_Rect textRect = { - m_x + 10 + 16, m_y + static_cast<int>(i * spacing), textSurface->w, textSurface->h}; + SDL_Rect textRect = {m_x + 10 + 16, m_y + (i * spacing), textSurface->w, textSurface->h}; SDL_RenderCopy(engine.renderer(), textTexture, nullptr, &textRect); - SDL_Texture* unit_texture = spritesheet->getUnitTextures() - .at(static_cast<int>(Faction::URED)) - .at(static_cast<int>(id)) - .at(static_cast<int>(UnitState::IDLE)) - .first; + SDL_Texture* unitTexture = spritesheet->getUnitTextures() + .at(static_cast<int>(Faction::URED)) + .at(static_cast<int>(id)) + .at(static_cast<int>(UnitState::IDLE)) + .first; - SDL_Rect trgt_rect = {m_x + 5, m_y + static_cast<int>(i * spacing), 16, 16}; + SDL_Rect targetRect = {m_x + 5, m_y + (i * spacing), 16, 16}; - SDL_Rect src_rect = {5, 0, 10, 10}; + SDL_Rect sourceRect = {5, 0, 10, 10}; - SDL_RenderCopy(engine.renderer(), unit_texture, &src_rect, &trgt_rect); + SDL_RenderCopy(engine.renderer(), unitTexture, &sourceRect, &targetRect); SDL_Surface* costSurface = TTF_RenderText_Solid( font, std::to_string(config.getUnitCost(id)).c_str(), (i == m_selectedOption) ? yellow : white); - if (!textSurface) + if (textSurface == nullptr) { continue; } SDL_Texture* costTexture = SDL_CreateTextureFromSurface(engine.renderer(), costSurface); - SDL_Rect cost_rect{ - m_x + 120, m_y + static_cast<int>(i * spacing), costSurface->w, costSurface->h}; - SDL_RenderCopy(engine.renderer(), costTexture, nullptr, &cost_rect); + SDL_Rect costRect{m_x + 120, m_y + (i * spacing), costSurface->w, costSurface->h}; + SDL_RenderCopy(engine.renderer(), costTexture, nullptr, &costRect); SDL_DestroyTexture(costTexture); SDL_FreeSurface(costSurface); @@ -133,7 +131,7 @@ void RecruitingMenu::render(Engine& engine) TTF_Quit(); } -void RecruitingMenu::handleEvent(Engine& engine, SDL_Event& event) +void RecruitingMenu::handleEvent(Engine& /*engine*/, SDL_Event& event) { if (event.type == SDL_KEYDOWN) { diff --git a/src/game/ui/context/RecruitingMenu.hpp b/src/game/ui/context/RecruitingMenu.hpp index b37e60d45e9e57da26b7bc22bb5326ffcde7ffe2..ad37cda3fb96ec2fd4ee7308f29c385ad920003f 100644 --- a/src/game/ui/context/RecruitingMenu.hpp +++ b/src/game/ui/context/RecruitingMenu.hpp @@ -12,7 +12,7 @@ class RecruitingMenu : public Scene public: UnitTypeId getSelectedOption(); - void handleEvent(Engine& engine, SDL_Event& event); + void handleEvent(Engine& engine, SDL_Event& event) override; void update(int x, int y); @@ -27,8 +27,8 @@ class RecruitingMenu : public Scene std::vector<UnitTypeId> m_options; int m_x; int m_y; - const std::unordered_map<UnitTypeId, std::string> unitNames; - std::unordered_map<int, UnitTypeId> cost2UnitId; + const std::unordered_map<UnitTypeId, std::string> m_unitNames; + std::unordered_map<int, UnitTypeId> m_cost2UnitId; UnitTypeId m_selectedId; void selectSprite(); diff --git a/src/game/ui/menu/EndScreen.hpp b/src/game/ui/menu/EndScreen.hpp index 806791cb55b9cb1799f68aae4446ce754afb8e54..8fc428a4b8c0b33593ddf63c1338b734925530ae 100644 --- a/src/game/ui/menu/EndScreen.hpp +++ b/src/game/ui/menu/EndScreen.hpp @@ -9,9 +9,9 @@ class Endscreen : public Scene { public: Endscreen(Player& player); - void render(Engine& engine); + void render(Engine& engine) override; - void handleEvent(Engine& engine, SDL_Event& event); + void handleEvent(Engine& engine, SDL_Event& event) override; private: SDL_Color m_color; diff --git a/src/game/ui/menu/Menu.cpp b/src/game/ui/menu/Menu.cpp index efdbb448af97afa3229f58c6a15564fed1636992..9d9cb4e11fe5a2b49be8482fc142a7281474bc99 100644 --- a/src/game/ui/menu/Menu.cpp +++ b/src/game/ui/menu/Menu.cpp @@ -15,15 +15,15 @@ namespace advanced_wars { -Menu::Menu(int selectedOption, const std::string& level_filepath) - : m_selectedOption(selectedOption), m_level_filepath(level_filepath), +Menu::Menu(int selectedOption, const std::string& levelFilepath) + : m_selectedOption(selectedOption), m_level_filepath(levelFilepath), m_options({"Start Game", "Options", "Exit"}), m_backgroundTexture(nullptr) { } Menu::~Menu() { - if (m_backgroundTexture) + if (m_backgroundTexture != nullptr) { SDL_DestroyTexture(m_backgroundTexture); } @@ -39,7 +39,7 @@ void Menu::render(Engine& engine) int windowWidth = engine.getWindow().w(); - if (m_backgroundTexture) + if (m_backgroundTexture != nullptr) { SDL_RenderCopy(engine.renderer(), m_backgroundTexture, nullptr, nullptr); } @@ -53,14 +53,14 @@ void Menu::render(Engine& engine) std::string relativePath = "res/ARCADECLASSIC.TTF"; std::string fullPath = basePath + relativePath; TTF_Font* titleFont = TTF_OpenFont(fullPath.c_str(), 48); - if (!titleFont) + if (titleFont == nullptr) { std::cerr << "Failed to load title font: " << fullPath << TTF_GetError() << "\n"; return; } TTF_Font* menuFont = TTF_OpenFont(fullPath.c_str(), 24); - if (!menuFont) + if (menuFont == nullptr) { TTF_CloseFont(titleFont); std::cerr << "Failed to load menu font: " << fullPath << TTF_GetError() << "\n"; @@ -71,12 +71,11 @@ void Menu::render(Engine& engine) SDL_Color yellow = {255, 255, 0, 255}; SDL_Surface* titleSurface = TTF_RenderText_Solid(titleFont, "Advanced Wars", white); - if (titleSurface) + if (titleSurface != nullptr) { SDL_Texture* titleTexture = SDL_CreateTextureFromSurface(engine.renderer(), titleSurface); SDL_Rect titleRect = { - static_cast<int>((windowWidth - titleSurface->w) / 2), 50, titleSurface->w, - titleSurface->h}; + ((windowWidth - titleSurface->w) / 2), 50, titleSurface->w, titleSurface->h}; SDL_RenderCopy(engine.renderer(), titleTexture, nullptr, &titleRect); SDL_DestroyTexture(titleTexture); SDL_FreeSurface(titleSurface); @@ -86,14 +85,14 @@ void Menu::render(Engine& engine) { SDL_Surface* textSurface = TTF_RenderText_Solid( menuFont, m_options[i].c_str(), (i == m_selectedOption) ? yellow : white); - if (!textSurface) + if (textSurface == nullptr) { continue; } SDL_Texture* textTexture = SDL_CreateTextureFromSurface(engine.renderer(), textSurface); SDL_Rect textRect = { - static_cast<int>((windowWidth - textSurface->w) / 2), static_cast<int>(150 + i * 50), - textSurface->w, textSurface->h}; + ((windowWidth - textSurface->w) / 2), static_cast<int>(150 + (i * 50)), textSurface->w, + textSurface->h}; SDL_RenderCopy(engine.renderer(), textTexture, nullptr, &textRect); SDL_DestroyTexture(textTexture); SDL_FreeSurface(textSurface); @@ -141,7 +140,7 @@ void Menu::loadBackground(Engine& engine, const std::string& imagePath) { // Lade das Hintergrundbild SDL_Surface* backgroundSurface = IMG_Load(imagePath.c_str()); - if (!backgroundSurface) + if (backgroundSurface == nullptr) { std::cerr << "Failed to load background image: " << IMG_GetError() << "\n"; return; @@ -153,7 +152,7 @@ void Menu::loadBackground(Engine& engine, const std::string& imagePath) SDL_FreeSurface(backgroundSurface); // Oberfläche freigeben, da sie nicht mehr // benötigt wird - if (!m_backgroundTexture) + if (m_backgroundTexture == nullptr) { std::cerr << "Failed to create background texture: " << SDL_GetError() << "\n"; } diff --git a/src/game/ui/menu/Menu.hpp b/src/game/ui/menu/Menu.hpp index f3482ba0a3e314816bd2da01ff2d23ef57a6d194..5080a8af9ef0088fa3e353f5d499cd17b87d13c2 100644 --- a/src/game/ui/menu/Menu.hpp +++ b/src/game/ui/menu/Menu.hpp @@ -31,7 +31,7 @@ class Menu : public Scene * @param selectedOption The index of the initially selected menu option. * @param level_filepath The path from which the level will be loaded. */ - Menu(int selectedOption, const std::string& level_filepath); + Menu(int selectedOption, const std::string& levelFilepath); /** * @brief Renders the menu on the screen. @@ -58,7 +58,7 @@ class Menu : public Scene * @param engine Pointer to the game engine, used to manage scenes. * @param event The SDL event containing user input data. */ - void handleEvent(Engine& engine, SDL_Event& event); + void handleEvent(Engine& engine, SDL_Event& event) override; /** * @brief Loads a background image as a texture. diff --git a/src/game/ui/menu/PauseMenu.cpp b/src/game/ui/menu/PauseMenu.cpp index 3bf5679dd17b81be64b301e9658834bc98ddd507..c2d152b33eb1cb60adee9784230938c66e7b62ce 100644 --- a/src/game/ui/menu/PauseMenu.cpp +++ b/src/game/ui/menu/PauseMenu.cpp @@ -17,7 +17,7 @@ PauseMenu::PauseMenu(int selectedOption, SDL_Texture* backgroundTexture) std::cerr << "Failed to initialize SDL_ttf: " << TTF_GetError() << "\n"; } - if (!m_backgroundTexture) + if (m_backgroundTexture == nullptr) { this->m_backgroundTexture = nullptr; } @@ -25,7 +25,7 @@ PauseMenu::PauseMenu(int selectedOption, SDL_Texture* backgroundTexture) PauseMenu::~PauseMenu() { - if (m_backgroundTexture) + if (m_backgroundTexture != nullptr) { SDL_DestroyTexture(m_backgroundTexture); m_backgroundTexture = nullptr; @@ -46,7 +46,7 @@ void PauseMenu::render(Engine& engine) // engine->render(); // Render the dialog background - if (m_backgroundTexture) + if (m_backgroundTexture != nullptr) { SDL_RenderCopy(renderer, m_backgroundTexture, nullptr, nullptr); } @@ -57,7 +57,7 @@ void PauseMenu::render(Engine& engine) std::string fullPath = basePath + relativePath; TTF_Font* font = TTF_OpenFont(fullPath.c_str(), 24); - if (!font) + if (font == nullptr) { std::cerr << "Failed to load menu font: " << fullPath << " " << TTF_GetError() << "\n"; return; @@ -72,7 +72,7 @@ void PauseMenu::render(Engine& engine) font, m_options[i].c_str(), (i == m_selectedOption) ? yellow : white); SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface); - SDL_Rect destRect = {100, static_cast<int>(100 + i * 50), textSurface->w, textSurface->h}; + SDL_Rect destRect = {100, static_cast<int>(100 + (i * 50)), textSurface->w, textSurface->h}; SDL_RenderCopy(renderer, textTexture, nullptr, &destRect); SDL_FreeSurface(textSurface); @@ -121,7 +121,7 @@ void PauseMenu::handleEvent(Engine& engine, SDL_Event& event) void PauseMenu::loadBackground(Engine& engine, const std::string& imagePath) { SDL_Surface* surface = IMG_Load(imagePath.c_str()); - if (!surface) + if (surface == nullptr) { std::cerr << "Failed to load image: " << IMG_GetError() << "\n"; return; diff --git a/src/game/ui/menu/PauseMenu.hpp b/src/game/ui/menu/PauseMenu.hpp index aa919e0bbe5b5b7d7e33afa6501d6fb30b27b195..e97308b1eaf13c977c89f3357eae50686dc8bbab 100644 --- a/src/game/ui/menu/PauseMenu.hpp +++ b/src/game/ui/menu/PauseMenu.hpp @@ -63,7 +63,7 @@ class PauseMenu : public Scene * @param engine Pointer to the game engine, used to manage scenes. * @param event The SDL event containing user input data. */ - void handleEvent(Engine& engine, SDL_Event& event); + void handleEvent(Engine& engine, SDL_Event& event) override; /** * @brief Loads a background image as a texture. diff --git a/src/game/ui/modals/HelpMenu.cpp b/src/game/ui/modals/HelpMenu.cpp index dc62236b4510821e51a636afe5c0f9a9f877a4c8..175df6cb9ecb03401cb0da6197c681c9a5c0e993 100644 --- a/src/game/ui/modals/HelpMenu.cpp +++ b/src/game/ui/modals/HelpMenu.cpp @@ -8,7 +8,7 @@ namespace advanced_wars HelpMenu::HelpMenu() {} -void HelpMenu::handleEvent(Engine& engine, SDL_Event& event) {} +void HelpMenu::handleEvent(Engine& /*engine*/, SDL_Event& /*event*/) {} std::vector<std::string> helpTable = { "Willkommen im Tutorial!", // 0 @@ -41,7 +41,7 @@ void HelpMenu::render(advanced_wars::Engine& engine) std::string relativePath = "res/ARCADECLASSIC.TTF"; std::string fullPath = basePath + relativePath; TTF_Font* font = TTF_OpenFont(fullPath.c_str(), 16); - if (!font) + if (font == nullptr) { std::cerr << "Failed to load font: " << TTF_GetError() << "\n"; return; @@ -50,27 +50,27 @@ void HelpMenu::render(advanced_wars::Engine& engine) SDL_Color white = {200, 200, 0, 255}; int spacing = 25; int boxWidth = 600; - int boxHeight = static_cast<int>(610); + int boxHeight = 610; SDL_SetRenderDrawColor(engine.renderer(), 75, 87, 219, 255); SDL_Rect box = {50, 50, boxWidth, boxHeight}; SDL_RenderFillRect(engine.renderer(), &box); - int text_x = 60; - int text_y = 60; + int textX = 60; + int textY = 60; - renderTextPortion(engine, helpTable[0], font, white, boxWidth, text_x, text_y); - text_y += spacing; + renderTextPortion(engine, helpTable[0], font, white, boxWidth, textX, textY); + textY += spacing; std::string text = helpTable[1] + helpTable[2] + helpTable[3] + helpTable[4] + helpTable[5]; - renderTextPortion(engine, text, font, white, boxWidth, text_x, text_y); - text_y += 150; + renderTextPortion(engine, text, font, white, boxWidth, textX, textY); + textY += 150; text = helpTable[6] + helpTable[7] + helpTable[8] + helpTable[9] + helpTable[10]; - renderTextPortion(engine, text, font, white, boxWidth, text_x, text_y); - text_y += 125; + renderTextPortion(engine, text, font, white, boxWidth, textX, textY); + textY += 125; - SDL_Rect divider = {60, text_y - 25, boxWidth - 20, 2}; + SDL_Rect divider = {60, textY - 25, boxWidth - 20, 2}; SDL_SetRenderDrawColor(engine.renderer(), 239, 235, 216, 255); SDL_RenderFillRect(engine.renderer(), ÷r); @@ -78,58 +78,60 @@ void HelpMenu::render(advanced_wars::Engine& engine) SDL_Texture* buildingTexture = spritesheet->getBuildingTextures().at(0); int renderingScale = 2; - SDL_Rect trgt_rect = {65, text_y, 16 * renderingScale, 16 * renderingScale * 2}; + SDL_Rect targetRect = {65, textY, 16 * renderingScale, 16 * renderingScale * 2}; - SDL_Rect src_rect = {0, 0, 16, 32}; + SDL_Rect sourceRect = {0, 0, 16, 32}; - SDL_RenderCopy(engine.renderer(), buildingTexture, &src_rect, &trgt_rect); + SDL_RenderCopy(engine.renderer(), buildingTexture, &sourceRect, &targetRect); renderTextPortion( engine, "Das ist das Hauptquartier! Wenn es faellt, haben Sie das Spiel verloren!", font, - white, boxWidth - 120 - 5, 120, text_y); + white, boxWidth - 120 - 5, 120, textY); - text_y += 48; - renderTexture(buildingTexture, engine, 55, text_y + 48, 16, 16); - renderTexture(buildingTexture, engine, 55, text_y + 96, 32, 16); - renderTexture(buildingTexture, engine, 55, text_y + 144, 48, 16); - renderTexture(buildingTexture, engine, 55, text_y + 192, 64, 16); + textY += 48; + renderTexture(buildingTexture, engine, 55, textY + 48, 16, 16); + renderTexture(buildingTexture, engine, 55, textY + 96, 32, 16); + renderTexture(buildingTexture, engine, 55, textY + 144, 48, 16); + renderTexture(buildingTexture, engine, 55, textY + 192, 64, 16); renderTextPortion( engine, "Nehmen Sie Staedte auf der Karte ein um jede Runde Geld fuer das Rekrutieren " " der Einheiten " "zu bekommen!", - font, white, boxWidth - 120 - 5, 120, text_y + 48); + font, white, boxWidth - 120 - 5, 120, textY + 48); renderTextPortion( engine, "Aus der Kaserne koennen Sie Landeinheiten anfordern!", font, white, - boxWidth - 120 - 5, 120, text_y + 96); + boxWidth - 120 - 5, 120, textY + 96); renderTextPortion( engine, "Mit einem Flughafen koennen Sie die Lufthoheit erkaempfen! Achten Sie auf " "Flugabwehr!", - font, white, boxWidth - 120 - 5, 120, text_y + 144); + font, white, boxWidth - 120 - 5, 120, textY + 144); renderTextPortion( engine, "Der Hafen stellt ihnen verschiedene Marineeinheiten zur Verfuegung! Um den Sieg " " zu " "erringen sollten Sie Ihre Flotte nicht vernachlaessigen!", - font, white, boxWidth - 120 - 5, 120, text_y + 192); + font, white, boxWidth - 120 - 5, 120, textY + 192); TTF_CloseFont(font); TTF_Quit(); } void HelpMenu::renderTextPortion( - Engine& engine, std::string text, TTF_Font* font, SDL_Color color, int boxWidth, int text_x, - int text_y) + Engine& engine, std::string text, TTF_Font* font, SDL_Color color, int boxWidth, int textX, + int textY) { SDL_Surface* textSurface = TTF_RenderUTF8_Solid_Wrapped(font, text.c_str(), color, boxWidth - 5); - if (!textSurface) + if (textSurface == nullptr) + { return; + } SDL_Texture* textTexture = SDL_CreateTextureFromSurface(engine.renderer(), textSurface); - SDL_Rect textRect = {text_x, text_y, textSurface->w, textSurface->h}; + SDL_Rect textRect = {textX, textY, textSurface->w, textSurface->h}; SDL_RenderCopy(engine.renderer(), textTexture, nullptr, &textRect); SDL_DestroyTexture(textTexture); @@ -137,16 +139,16 @@ void HelpMenu::renderTextPortion( } void HelpMenu::renderTexture( - SDL_Texture* texture, Engine& engine, int x, int y, int src_x, int src_y) + SDL_Texture* texture, Engine& engine, int /*x*/, int y, int srcX, int srcY) { SDL_Texture* buildingTexture = texture; int renderingScale = 2; - SDL_Rect trgt_rect = {65, y, 16 * renderingScale, 16 * renderingScale}; + SDL_Rect targetRect = {65, y, 16 * renderingScale, 16 * renderingScale}; - SDL_Rect src_rect = {src_x, src_y, 16, 16}; + SDL_Rect sourceRect = {srcX, srcY, 16, 16}; - SDL_RenderCopy(engine.renderer(), buildingTexture, &src_rect, &trgt_rect); + SDL_RenderCopy(engine.renderer(), buildingTexture, &sourceRect, &targetRect); } } // namespace advanced_wars diff --git a/src/game/ui/modals/HelpMenu.hpp b/src/game/ui/modals/HelpMenu.hpp index 19b23313c26909b80275eba6271b3d64ebf484a9..8e484e5c5a7f7a9a067135ecb63c3884a74798da 100644 --- a/src/game/ui/modals/HelpMenu.hpp +++ b/src/game/ui/modals/HelpMenu.hpp @@ -26,10 +26,9 @@ class HelpMenu : public Scene void renderTextPortion( Engine& engine, std::string text, TTF_Font* font, SDL_Color color, int boxWidth, - int text_x, int text_y); + int textX, int textY); - void - renderTexture(SDL_Texture* texture, Engine& engine, int x, int y, int src_x, int src_y); + void renderTexture(SDL_Texture* texture, Engine& engine, int x, int y, int srcX, int srcY); }; } // namespace advanced_wars diff --git a/src/game/ui/modals/UnitInfoMenu.cpp b/src/game/ui/modals/UnitInfoMenu.cpp index 3fc2284b143d7b1fafe00e6319529489d2a44cc9..3b43b2af9a48cae5c2fd68257aaa850a203b7ee5 100644 --- a/src/game/ui/modals/UnitInfoMenu.cpp +++ b/src/game/ui/modals/UnitInfoMenu.cpp @@ -60,12 +60,7 @@ std::unordered_map<UnitTypeId, std::string> unitDescriptions = { { UnitTypeId::SUBMARINE, "U-Boot Versteckt sich und kann Ueberwasserziele angreifen"} }; -void UnitInfoMenu::handleEvent(Engine& engine, SDL_Event& event) -{ - // Hier kannst du den Code hinzufügen, um die Ereignisse für das UnitInfoMenu zu behandeln - // Wenn keine spezifische Ereignisbehandlung erforderlich ist, kann diese Methode auch leer - // bleiben. -} +void UnitInfoMenu::handleEvent(Engine& /*engine*/, SDL_Event& /*event*/) {} void UnitInfoMenu::setUnit(Unit& unit) { @@ -75,8 +70,10 @@ void UnitInfoMenu::setUnit(Unit& unit) void UnitInfoMenu::render(Engine& engine) { - if (!m_currentUnit || !m_isVisible) + if ((m_currentUnit == nullptr) || !m_isVisible) + { return; + } // TTF Initialisierung if (TTF_Init() == -1) @@ -89,7 +86,7 @@ void UnitInfoMenu::render(Engine& engine) std::string fullPath = basePath + "res/ARCADECLASSIC.TTF"; TTF_Font* font = TTF_OpenFont(fullPath.c_str(), 16); - if (!font) + if (font == nullptr) { std::cerr << "Failed to load font: " << TTF_GetError() << "\n"; return; @@ -100,7 +97,7 @@ void UnitInfoMenu::render(Engine& engine) UnitTypeId unitId = m_currentUnit->getUnitTypeId(); // Textzeilen, einschließlich der Beschreibung - std::vector<std::string> info_lines = { + std::vector<std::string> infoLines = { "HP " + std::to_string(m_currentUnit->getHealth()), "Movement " + std::to_string(m_currentUnit->getMovementPoints()), "Ammo " + std::to_string(m_currentUnit->getAmmo()), @@ -109,26 +106,28 @@ void UnitInfoMenu::render(Engine& engine) unitDescriptions[unitId] // Beschreibung einfügen }; - int max_text_width = 0; - int total_height = 0; + int maxTextWidth = 0; + int totalHeight = 0; std::vector<SDL_Texture*> textures; - for (const auto& line : info_lines) + for (const auto& line : infoLines) { SDL_Surface* textSurface = TTF_RenderText_Solid(font, line.c_str(), yellow); - if (!textSurface) + if (textSurface == nullptr) + { continue; + } - max_text_width = std::max(max_text_width, textSurface->w); - total_height += textSurface->h + spacing; + maxTextWidth = std::max(maxTextWidth, textSurface->w); + totalHeight += textSurface->h + spacing; SDL_Texture* textTexture = SDL_CreateTextureFromSurface(engine.renderer(), textSurface); textures.push_back(textTexture); SDL_FreeSurface(textSurface); } - int width = std::max(max_text_width + 20 * RENDERING_SCALE, 16 * RENDERING_SCALE + 20); - int height = - total_height + 30 * RENDERING_SCALE; // Die Höhe anpassen, um alle Textzeilen zu integrieren + int width = std::max(maxTextWidth + (20 * RENDERING_SCALE), (16 * RENDERING_SCALE) + 20); + int height = totalHeight + + (30 * RENDERING_SCALE); // Die Höhe anpassen, um alle Textzeilen zu integrieren SDL_Rect box = {m_x, m_y, width, height}; SDL_SetRenderDrawColor(engine.renderer(), 75, 87, 219, 255); // Schwarzes Hintergrundrechteck @@ -139,26 +138,27 @@ void UnitInfoMenu::render(Engine& engine) // Render unit sprite Spritesheet* spritesheet = engine.getSpritesheet(); - SDL_Texture* unit_texture = spritesheet->getUnitTextures() - .at(static_cast<int>(m_currentUnit->getFaction())) - .at(static_cast<int>(unitId)) - .at(static_cast<int>(UnitState::IDLE)) - .first; + SDL_Texture* unitTexture = spritesheet->getUnitTextures() + .at(static_cast<int>(m_currentUnit->getFaction())) + .at(static_cast<int>(unitId)) + .at(static_cast<int>(UnitState::IDLE)) + .first; - SDL_Rect sprite_rect = {m_x + 10, m_y + 10, 16 * RENDERING_SCALE, 16 * RENDERING_SCALE}; - SDL_Rect source_rect = {0, 0, 16, 16}; - SDL_RenderCopy(engine.renderer(), unit_texture, &source_rect, &sprite_rect); + SDL_Rect spriteRect = {m_x + 10, m_y + 10, 16 * RENDERING_SCALE, 16 * RENDERING_SCALE}; + SDL_Rect sourceRect = {0, 0, 16, 16}; + SDL_RenderCopy(engine.renderer(), unitTexture, &sourceRect, &spriteRect); // Text zeichnen - int text_y = m_y + 20 * RENDERING_SCALE; // Starte etwas unterhalb des Sprites + int textY = m_y + (20 * RENDERING_SCALE); // Starte etwas unterhalb des Sprites for (auto* texture : textures) { - int w, h; + int w; + int h; SDL_QueryTexture(texture, nullptr, nullptr, &w, &h); - SDL_Rect textRect = {m_x + 10, text_y, w, h}; + SDL_Rect textRect = {m_x + 10, textY, w, h}; SDL_RenderCopy(engine.renderer(), texture, nullptr, &textRect); SDL_DestroyTexture(texture); - text_y += (h + spacing); + textY += (h + spacing); } TTF_CloseFont(font); diff --git a/src/game/ui/modals/UnitInfoMenu.hpp b/src/game/ui/modals/UnitInfoMenu.hpp index 57f2522cf5f4b273cd8a6e9d3b98ff6849466bb0..08c3183b7d5192336480b55c63d387364c00d531 100644 --- a/src/game/ui/modals/UnitInfoMenu.hpp +++ b/src/game/ui/modals/UnitInfoMenu.hpp @@ -16,15 +16,15 @@ class UnitInfoMenu : public Scene void handleEvent(Engine& engine, SDL_Event& event) override; void setUnit(Unit& unit); - void render(Engine& engine); + void render(Engine& engine) override; void update(int x, int y); private: - int RENDERING_SCALE = 3; - int m_x; - int m_y; - Unit* m_currentUnit; - bool m_isVisible; + const int RENDERING_SCALE = 3; + int m_x; + int m_y; + Unit* m_currentUnit; + bool m_isVisible; std::string getMovementTypeString(MovementType type); };