1#include "map.h"
2
3#include <base/system.h>
4
5#include <game/editor/editor.h>
6#include <game/editor/mapitems/image.h>
7#include <game/editor/mapitems/layer_front.h>
8#include <game/editor/mapitems/layer_game.h>
9#include <game/editor/mapitems/layer_group.h>
10#include <game/editor/mapitems/layer_quads.h>
11#include <game/editor/mapitems/layer_sounds.h>
12#include <game/editor/mapitems/layer_tiles.h>
13#include <game/editor/mapitems/sound.h>
14#include <game/editor/references.h>
15
16void CEditorMap::CMapInfo::Reset()
17{
18 m_aAuthor[0] = '\0';
19 m_aVersion[0] = '\0';
20 m_aCredits[0] = '\0';
21 m_aLicense[0] = '\0';
22}
23
24void CEditorMap::CMapInfo::Copy(const CMapInfo &Source)
25{
26 str_copy(dst&: m_aAuthor, src: Source.m_aAuthor);
27 str_copy(dst&: m_aVersion, src: Source.m_aVersion);
28 str_copy(dst&: m_aCredits, src: Source.m_aCredits);
29 str_copy(dst&: m_aLicense, src: Source.m_aLicense);
30}
31
32void CEditorMap::OnModify()
33{
34 m_Modified = true;
35 m_ModifiedAuto = true;
36 m_LastModifiedTime = Editor()->Client()->GlobalTime();
37}
38
39void CEditorMap::ResetModifiedState()
40{
41 m_Modified = false;
42 m_ModifiedAuto = false;
43 m_LastModifiedTime = -1.0f;
44 m_LastSaveTime = Editor()->Client()->GlobalTime();
45}
46
47std::shared_ptr<CEnvelope> CEditorMap::NewEnvelope(CEnvelope::EType Type)
48{
49 OnModify();
50 std::shared_ptr<CEnvelope> pEnvelope = std::make_shared<CEnvelope>(args&: Type);
51 if(Type == CEnvelope::EType::COLOR)
52 {
53 pEnvelope->AddPoint(Time: CFixedTime::FromSeconds(Seconds: 0.0f), aValues: {f2fx(v: 1.0f), f2fx(v: 1.0f), f2fx(v: 1.0f), f2fx(v: 1.0f)});
54 pEnvelope->AddPoint(Time: CFixedTime::FromSeconds(Seconds: 1.0f), aValues: {f2fx(v: 1.0f), f2fx(v: 1.0f), f2fx(v: 1.0f), f2fx(v: 1.0f)});
55 }
56 else
57 {
58 pEnvelope->AddPoint(Time: CFixedTime::FromSeconds(Seconds: 0.0f), aValues: {0, 0, 0, 0});
59 pEnvelope->AddPoint(Time: CFixedTime::FromSeconds(Seconds: 1.0f), aValues: {0, 0, 0, 0});
60 }
61 m_vpEnvelopes.push_back(x: pEnvelope);
62 return pEnvelope;
63}
64
65void CEditorMap::InsertEnvelope(int Index, std::shared_ptr<CEnvelope> &pEnvelope)
66{
67 if(Index < 0 || Index >= (int)m_vpEnvelopes.size() + 1)
68 return;
69 m_vpEnvelopes.push_back(x: pEnvelope);
70 m_pEditor->m_SelectedEnvelope = MoveEnvelope(IndexFrom: (int)m_vpEnvelopes.size() - 1, IndexTo: Index);
71}
72
73void CEditorMap::UpdateEnvelopeReferences(int Index, std::shared_ptr<CEnvelope> &pEnvelope, std::vector<std::shared_ptr<IEditorEnvelopeReference>> &vpEditorObjectReferences)
74{
75 // update unrestored quad and soundsource references
76 for(auto &pEditorObjRef : vpEditorObjectReferences)
77 pEditorObjRef->SetEnvelope(pEnvelope, EnvIndex: Index);
78}
79
80std::vector<std::shared_ptr<IEditorEnvelopeReference>> CEditorMap::DeleteEnvelope(int Index)
81{
82 if(Index < 0 || Index >= (int)m_vpEnvelopes.size())
83 return std::vector<std::shared_ptr<IEditorEnvelopeReference>>();
84
85 OnModify();
86
87 std::vector<std::shared_ptr<IEditorEnvelopeReference>> vpEditorObjectReferences = VisitEnvelopeReferences(Visitor: [Index](int &ElementIndex) {
88 if(ElementIndex == Index)
89 {
90 ElementIndex = -1;
91 return true;
92 }
93 else if(ElementIndex > Index)
94 ElementIndex--;
95 return false;
96 });
97
98 m_vpEnvelopes.erase(position: m_vpEnvelopes.begin() + Index);
99 return vpEditorObjectReferences;
100}
101
102int CEditorMap::MoveEnvelope(int IndexFrom, int IndexTo)
103{
104 if(IndexFrom < 0 || IndexFrom >= (int)m_vpEnvelopes.size())
105 return IndexFrom;
106 if(IndexTo < 0 || IndexTo >= (int)m_vpEnvelopes.size())
107 return IndexFrom;
108 if(IndexFrom == IndexTo)
109 return IndexFrom;
110
111 OnModify();
112
113 VisitEnvelopeReferences(Visitor: [IndexFrom, IndexTo](int &ElementIndex) {
114 if(ElementIndex == IndexFrom)
115 ElementIndex = IndexTo;
116 else if(IndexFrom < IndexTo && ElementIndex > IndexFrom && ElementIndex <= IndexTo)
117 ElementIndex--;
118 else if(IndexTo < IndexFrom && ElementIndex < IndexFrom && ElementIndex >= IndexTo)
119 ElementIndex++;
120 return false;
121 });
122
123 auto pMovedEnvelope = m_vpEnvelopes[IndexFrom];
124 m_vpEnvelopes.erase(position: m_vpEnvelopes.begin() + IndexFrom);
125 m_vpEnvelopes.insert(position: m_vpEnvelopes.begin() + IndexTo, x: pMovedEnvelope);
126
127 return IndexTo;
128}
129
130template<typename F>
131std::vector<std::shared_ptr<IEditorEnvelopeReference>> CEditorMap::VisitEnvelopeReferences(F &&Visitor)
132{
133 std::vector<std::shared_ptr<IEditorEnvelopeReference>> vpUpdatedReferences;
134 for(auto &pGroup : m_vpGroups)
135 {
136 for(auto &pLayer : pGroup->m_vpLayers)
137 {
138 if(pLayer->m_Type == LAYERTYPE_QUADS)
139 {
140 std::shared_ptr<CLayerQuads> pLayerQuads = std::static_pointer_cast<CLayerQuads>(r: pLayer);
141 std::shared_ptr<CLayerQuadsEnvelopeReference> pQuadLayerReference = std::make_shared<CLayerQuadsEnvelopeReference>(args&: pLayerQuads);
142 for(int QuadId = 0; QuadId < (int)pLayerQuads->m_vQuads.size(); ++QuadId)
143 {
144 auto &Quad = pLayerQuads->m_vQuads[QuadId];
145 if(Visitor(Quad.m_PosEnv))
146 pQuadLayerReference->AddQuadIndex(QuadIndex: QuadId);
147 if(Visitor(Quad.m_ColorEnv))
148 pQuadLayerReference->AddQuadIndex(QuadIndex: QuadId);
149 }
150 if(!pQuadLayerReference->Empty())
151 vpUpdatedReferences.push_back(x: pQuadLayerReference);
152 }
153 else if(pLayer->m_Type == LAYERTYPE_TILES)
154 {
155 std::shared_ptr<CLayerTiles> pLayerTiles = std::static_pointer_cast<CLayerTiles>(r: pLayer);
156 std::shared_ptr<CLayerTilesEnvelopeReference> pTileLayerReference = std::make_shared<CLayerTilesEnvelopeReference>(args&: pLayerTiles);
157 if(Visitor(pLayerTiles->m_ColorEnv))
158 vpUpdatedReferences.push_back(x: pTileLayerReference);
159 }
160 else if(pLayer->m_Type == LAYERTYPE_SOUNDS)
161 {
162 std::shared_ptr<CLayerSounds> pLayerSounds = std::static_pointer_cast<CLayerSounds>(r: pLayer);
163 std::shared_ptr<CLayerSoundEnvelopeReference> pSoundLayerReference = std::make_shared<CLayerSoundEnvelopeReference>(args&: pLayerSounds);
164
165 for(int SourceId = 0; SourceId < (int)pLayerSounds->m_vSources.size(); ++SourceId)
166 {
167 auto &Source = pLayerSounds->m_vSources[SourceId];
168 if(Visitor(Source.m_PosEnv))
169 pSoundLayerReference->AddSoundSourceIndex(SoundSourceIndex: SourceId);
170 if(Visitor(Source.m_SoundEnv))
171 pSoundLayerReference->AddSoundSourceIndex(SoundSourceIndex: SourceId);
172 }
173 if(!pSoundLayerReference->Empty())
174 vpUpdatedReferences.push_back(x: pSoundLayerReference);
175 }
176 }
177 }
178 return vpUpdatedReferences;
179}
180
181std::shared_ptr<CLayerGroup> CEditorMap::NewGroup()
182{
183 OnModify();
184 std::shared_ptr<CLayerGroup> pGroup = std::make_shared<CLayerGroup>(args: this);
185 m_vpGroups.push_back(x: pGroup);
186 return pGroup;
187}
188
189int CEditorMap::MoveGroup(int IndexFrom, int IndexTo)
190{
191 if(IndexFrom < 0 || IndexFrom >= (int)m_vpGroups.size())
192 return IndexFrom;
193 if(IndexTo < 0 || IndexTo >= (int)m_vpGroups.size())
194 return IndexFrom;
195 if(IndexFrom == IndexTo)
196 return IndexFrom;
197 OnModify();
198 auto pMovedGroup = m_vpGroups[IndexFrom];
199 m_vpGroups.erase(position: m_vpGroups.begin() + IndexFrom);
200 m_vpGroups.insert(position: m_vpGroups.begin() + IndexTo, x: pMovedGroup);
201 return IndexTo;
202}
203
204void CEditorMap::DeleteGroup(int Index)
205{
206 if(Index < 0 || Index >= (int)m_vpGroups.size())
207 return;
208 OnModify();
209 m_vpGroups.erase(position: m_vpGroups.begin() + Index);
210}
211
212void CEditorMap::ModifyImageIndex(const FIndexModifyFunction &IndexModifyFunction)
213{
214 OnModify();
215 for(auto &pGroup : m_vpGroups)
216 {
217 pGroup->ModifyImageIndex(IndexModifyFunction);
218 }
219}
220
221void CEditorMap::ModifyEnvelopeIndex(const FIndexModifyFunction &IndexModifyFunction)
222{
223 OnModify();
224 for(auto &pGroup : m_vpGroups)
225 {
226 pGroup->ModifyEnvelopeIndex(IndexModifyFunction);
227 }
228}
229
230void CEditorMap::ModifySoundIndex(const FIndexModifyFunction &IndexModifyFunction)
231{
232 OnModify();
233 for(auto &pGroup : m_vpGroups)
234 {
235 pGroup->ModifySoundIndex(IndexModifyFunction);
236 }
237}
238
239void CEditorMap::Clean()
240{
241 ResetModifiedState();
242
243 m_vpGroups.clear();
244 m_vpEnvelopes.clear();
245 m_vpImages.clear();
246 m_vpSounds.clear();
247 m_vSettings.clear();
248
249 m_pGameGroup = nullptr;
250 m_pGameLayer = nullptr;
251 m_pTeleLayer = nullptr;
252 m_pSpeedupLayer = nullptr;
253 m_pFrontLayer = nullptr;
254 m_pSwitchLayer = nullptr;
255 m_pTuneLayer = nullptr;
256
257 m_MapInfo.Reset();
258 m_MapInfoTmp.Reset();
259
260 m_EditorHistory.Clear();
261 m_EnvelopeEditorHistory.Clear();
262 m_ServerSettingsHistory.Clear();
263 m_EnvOpTracker.Reset();
264
265 m_SelectedImage = 0;
266 m_SelectedSound = 0;
267}
268
269void CEditorMap::CreateDefault()
270{
271 // Add default background group, quad layer and quad
272 std::shared_ptr<CLayerGroup> pGroup = NewGroup();
273 pGroup->m_ParallaxX = 0;
274 pGroup->m_ParallaxY = 0;
275 std::shared_ptr<CLayerQuads> pLayer = std::make_shared<CLayerQuads>(args: this);
276 CQuad *pQuad = pLayer->NewQuad(x: 0, y: 0, Width: 1600, Height: 1200);
277 pQuad->m_aColors[0].r = pQuad->m_aColors[1].r = 94;
278 pQuad->m_aColors[0].g = pQuad->m_aColors[1].g = 132;
279 pQuad->m_aColors[0].b = pQuad->m_aColors[1].b = 174;
280 pQuad->m_aColors[2].r = pQuad->m_aColors[3].r = 204;
281 pQuad->m_aColors[2].g = pQuad->m_aColors[3].g = 232;
282 pQuad->m_aColors[2].b = pQuad->m_aColors[3].b = 255;
283 pGroup->AddLayer(pLayer);
284
285 // Add game group and layer
286 MakeGameGroup(pGroup: NewGroup());
287 MakeGameLayer(pLayer: std::make_shared<CLayerGame>(args: this, args: 50, args: 50));
288 m_pGameGroup->AddLayer(pLayer: m_pGameLayer);
289
290 ResetModifiedState();
291 CheckIntegrity();
292}
293
294void CEditorMap::CheckIntegrity()
295{
296 const auto &&CheckObjectInMap = [&](const CMapObject *pMapObject, const char *pName) {
297 dbg_assert(pMapObject != nullptr, "%s missing in map", pName);
298 dbg_assert(pMapObject->Map() == this, "%s does not belong to map (object_map=%p, this_map=%p)", pName, pMapObject->Map(), this);
299 };
300 bool GameGroupMissing = true;
301 CheckObjectInMap(m_pGameGroup.get(), "Game group");
302 dbg_assert(m_pGameGroup->m_GameGroup, "Game group not marked as such");
303 bool GameLayerMissing = true;
304 CheckObjectInMap(m_pGameLayer.get(), "Game layer");
305 dbg_assert(m_pGameLayer->m_HasGame, "Game layer not marked as such");
306 bool FrontLayerMissing = false;
307 if(m_pFrontLayer != nullptr)
308 {
309 FrontLayerMissing = true;
310 CheckObjectInMap(m_pFrontLayer.get(), "Front layer");
311 dbg_assert(m_pFrontLayer->m_HasFront, "Front layer not marked as such");
312 }
313 bool TeleLayerMissing = false;
314 if(m_pTeleLayer != nullptr)
315 {
316 TeleLayerMissing = true;
317 CheckObjectInMap(m_pTeleLayer.get(), "Tele layer");
318 dbg_assert(m_pTeleLayer->m_HasTele, "Tele layer not marked as such");
319 }
320 bool SpeedupLayerMissing = false;
321 if(m_pSpeedupLayer != nullptr)
322 {
323 SpeedupLayerMissing = true;
324 CheckObjectInMap(m_pSpeedupLayer.get(), "Speedup layer");
325 dbg_assert(m_pSpeedupLayer->m_HasSpeedup, "Speedup layer not marked as such");
326 }
327 bool SwitchLayerMissing = false;
328 if(m_pSwitchLayer != nullptr)
329 {
330 SwitchLayerMissing = true;
331 CheckObjectInMap(m_pSwitchLayer.get(), "Switch layer");
332 dbg_assert(m_pSwitchLayer->m_HasSwitch, "Switch layer not marked as such");
333 }
334 bool TuneLayerMissing = false;
335 if(m_pTuneLayer != nullptr)
336 {
337 TuneLayerMissing = true;
338 CheckObjectInMap(m_pTuneLayer.get(), "Tune layer");
339 dbg_assert(m_pTuneLayer->m_HasTune, "Tune layer not marked as such");
340 }
341 for(const auto &pGroup : m_vpGroups)
342 {
343 CheckObjectInMap(pGroup.get(), "Group");
344 for(const auto &pLayer : pGroup->m_vpLayers)
345 {
346 CheckObjectInMap(pLayer.get(), "Layer");
347 }
348 if(pGroup == m_pGameGroup)
349 {
350 GameGroupMissing = false;
351 for(const auto &pLayer : pGroup->m_vpLayers)
352 {
353 if(pLayer == m_pGameLayer)
354 {
355 GameLayerMissing = false;
356 }
357 if(pLayer == m_pFrontLayer)
358 {
359 FrontLayerMissing = false;
360 }
361 if(pLayer == m_pTeleLayer)
362 {
363 TeleLayerMissing = false;
364 }
365 if(pLayer == m_pSpeedupLayer)
366 {
367 SpeedupLayerMissing = false;
368 }
369 if(pLayer == m_pSwitchLayer)
370 {
371 SwitchLayerMissing = false;
372 }
373 if(pLayer == m_pTuneLayer)
374 {
375 TuneLayerMissing = false;
376 }
377 }
378 dbg_assert(!GameLayerMissing, "Game layer missing in game group");
379 dbg_assert(!FrontLayerMissing, "Front layer missing in game group");
380 dbg_assert(!TeleLayerMissing, "Tele layer missing in game group");
381 dbg_assert(!SpeedupLayerMissing, "Speedup layer missing in game group");
382 dbg_assert(!SwitchLayerMissing, "Switch layer missing in game group");
383 dbg_assert(!TuneLayerMissing, "Tune layer missing in game group");
384 }
385 }
386 dbg_assert(!GameGroupMissing, "Game group missing in list of groups");
387 for(const auto &pImage : m_vpImages)
388 {
389 CheckObjectInMap(pImage.get(), "Image");
390 }
391 for(const auto &pSound : m_vpSounds)
392 {
393 CheckObjectInMap(pSound.get(), "Sound");
394 }
395}
396
397void CEditorMap::MakeGameLayer(const std::shared_ptr<CLayer> &pLayer)
398{
399 m_pGameLayer = std::static_pointer_cast<CLayerGame>(r: pLayer);
400}
401
402void CEditorMap::MakeGameGroup(std::shared_ptr<CLayerGroup> pGroup)
403{
404 m_pGameGroup = std::move(pGroup);
405 m_pGameGroup->m_GameGroup = true;
406 str_copy(dst&: m_pGameGroup->m_aName, src: "Game");
407}
408
409void CEditorMap::MakeTeleLayer(const std::shared_ptr<CLayer> &pLayer)
410{
411 m_pTeleLayer = std::static_pointer_cast<CLayerTele>(r: pLayer);
412}
413
414void CEditorMap::MakeSpeedupLayer(const std::shared_ptr<CLayer> &pLayer)
415{
416 m_pSpeedupLayer = std::static_pointer_cast<CLayerSpeedup>(r: pLayer);
417}
418
419void CEditorMap::MakeFrontLayer(const std::shared_ptr<CLayer> &pLayer)
420{
421 m_pFrontLayer = std::static_pointer_cast<CLayerFront>(r: pLayer);
422}
423
424void CEditorMap::MakeSwitchLayer(const std::shared_ptr<CLayer> &pLayer)
425{
426 m_pSwitchLayer = std::static_pointer_cast<CLayerSwitch>(r: pLayer);
427}
428
429void CEditorMap::MakeTuneLayer(const std::shared_ptr<CLayer> &pLayer)
430{
431 m_pTuneLayer = std::static_pointer_cast<CLayerTune>(r: pLayer);
432}
433
434std::shared_ptr<CEditorImage> CEditorMap::SelectedImage() const
435{
436 if(m_SelectedImage < 0 || (size_t)m_SelectedImage >= m_vpImages.size())
437 {
438 return nullptr;
439 }
440 return m_vpImages[m_SelectedImage];
441}
442
443void CEditorMap::SelectImage(const std::shared_ptr<CEditorImage> &pImage)
444{
445 for(size_t i = 0; i < m_vpImages.size(); ++i)
446 {
447 if(m_vpImages[i] == pImage)
448 {
449 m_SelectedImage = i;
450 break;
451 }
452 }
453}
454
455void CEditorMap::SelectNextImage()
456{
457 const int OldImage = m_SelectedImage;
458 m_SelectedImage = std::clamp(val: m_SelectedImage, lo: 0, hi: (int)m_vpImages.size() - 1);
459 for(size_t i = m_SelectedImage + 1; i < m_vpImages.size(); i++)
460 {
461 if(m_vpImages[i]->m_External == m_vpImages[m_SelectedImage]->m_External)
462 {
463 m_SelectedImage = i;
464 break;
465 }
466 }
467 if(m_SelectedImage == OldImage && !m_vpImages[m_SelectedImage]->m_External)
468 {
469 for(size_t i = 0; i < m_vpImages.size(); i++)
470 {
471 if(m_vpImages[i]->m_External)
472 {
473 m_SelectedImage = i;
474 break;
475 }
476 }
477 }
478}
479
480void CEditorMap::SelectPreviousImage()
481{
482 const int OldImage = m_SelectedImage;
483 m_SelectedImage = std::clamp(val: m_SelectedImage, lo: 0, hi: (int)m_vpImages.size() - 1);
484 for(int i = m_SelectedImage - 1; i >= 0; i--)
485 {
486 if(m_vpImages[i]->m_External == m_vpImages[m_SelectedImage]->m_External)
487 {
488 m_SelectedImage = i;
489 break;
490 }
491 }
492 if(m_SelectedImage == OldImage && m_vpImages[m_SelectedImage]->m_External)
493 {
494 for(int i = (int)m_vpImages.size() - 1; i >= 0; i--)
495 {
496 if(!m_vpImages[i]->m_External)
497 {
498 m_SelectedImage = i;
499 break;
500 }
501 }
502 }
503}
504
505bool CEditorMap::IsImageUsed(int ImageIndex) const
506{
507 for(const auto &pGroup : m_vpGroups)
508 {
509 for(const auto &pLayer : pGroup->m_vpLayers)
510 {
511 if(pLayer->m_Type == LAYERTYPE_TILES)
512 {
513 const std::shared_ptr<CLayerTiles> pTiles = std::static_pointer_cast<CLayerTiles>(r: pLayer);
514 if(pTiles->m_Image == ImageIndex)
515 {
516 return true;
517 }
518 }
519 else if(pLayer->m_Type == LAYERTYPE_QUADS)
520 {
521 const std::shared_ptr<CLayerQuads> pQuads = std::static_pointer_cast<CLayerQuads>(r: pLayer);
522 if(pQuads->m_Image == ImageIndex)
523 {
524 return true;
525 }
526 }
527 }
528 }
529 return false;
530}
531
532std::vector<int> CEditorMap::SortImages()
533{
534 static const auto &&s_ImageNameComparator = [](const std::shared_ptr<CEditorImage> &pLhs, const std::shared_ptr<CEditorImage> &pRhs) {
535 return str_comp(a: pLhs->m_aName, b: pRhs->m_aName) < 0;
536 };
537 if(std::is_sorted(first: m_vpImages.begin(), last: m_vpImages.end(), comp: s_ImageNameComparator))
538 {
539 return std::vector<int>();
540 }
541
542 const std::vector<std::shared_ptr<CEditorImage>> vpTemp = m_vpImages;
543 std::vector<int> vSortedIndex;
544 vSortedIndex.resize(new_size: vpTemp.size());
545
546 std::sort(first: m_vpImages.begin(), last: m_vpImages.end(), comp: s_ImageNameComparator);
547 for(size_t OldIndex = 0; OldIndex < vpTemp.size(); OldIndex++)
548 {
549 for(size_t NewIndex = 0; NewIndex < m_vpImages.size(); NewIndex++)
550 {
551 if(vpTemp[OldIndex] == m_vpImages[NewIndex])
552 {
553 vSortedIndex[OldIndex] = NewIndex;
554 break;
555 }
556 }
557 }
558 ModifyImageIndex(IndexModifyFunction: [vSortedIndex](int *pIndex) {
559 if(*pIndex >= 0)
560 {
561 *pIndex = vSortedIndex[*pIndex];
562 }
563 });
564
565 return vSortedIndex;
566}
567
568std::shared_ptr<CEditorSound> CEditorMap::SelectedSound() const
569{
570 if(m_SelectedSound < 0 || (size_t)m_SelectedSound >= m_vpSounds.size())
571 {
572 return nullptr;
573 }
574 return m_vpSounds[m_SelectedSound];
575}
576
577void CEditorMap::SelectSound(const std::shared_ptr<CEditorSound> &pSound)
578{
579 for(size_t i = 0; i < m_vpSounds.size(); ++i)
580 {
581 if(m_vpSounds[i] == pSound)
582 {
583 m_SelectedSound = i;
584 break;
585 }
586 }
587}
588
589void CEditorMap::SelectNextSound()
590{
591 m_SelectedSound = (m_SelectedSound + 1) % m_vpSounds.size();
592}
593
594void CEditorMap::SelectPreviousSound()
595{
596 m_SelectedSound = (m_SelectedSound + m_vpSounds.size() - 1) % m_vpSounds.size();
597}
598
599bool CEditorMap::IsSoundUsed(int SoundIndex) const
600{
601 for(const auto &pGroup : m_vpGroups)
602 {
603 for(const auto &pLayer : pGroup->m_vpLayers)
604 {
605 if(pLayer->m_Type == LAYERTYPE_SOUNDS)
606 {
607 std::shared_ptr<CLayerSounds> pSounds = std::static_pointer_cast<CLayerSounds>(r: pLayer);
608 if(pSounds->m_Sound == SoundIndex)
609 {
610 return true;
611 }
612 }
613 }
614 }
615 return false;
616}
617